MICHAEL ONTIVEROS

There are some existing typos in the tables in addition to those produced during the use of Magick. I made some assumptions along the way, documenting them. These need to be checked for accuracy.

Disclaimer: The purpose of the Open Case Studies project is to demonstrate the use of various data science methods, tools, and software in the context of messy, real-world data. A given case study does not cover all aspects of the research process, is not claiming to be the most appropriate way to analyze a given data set, and should not be used in the context of making policy decisions without external consultation from scientific experts.

This work is licensed under the Creative Commons Attribution-NonCommercial 3.0 (CC BY-NC 3.0) United States License.

To cite this case study please use:

Wright, Carrie, and Ontiveros, Michael and Jager, Leah and Taub, Margaret and Hicks, Stephanie. (2020). https://github.com/opencasestudies/ocs-youth-disconnection-case-study. Disparities in Youth Disconnection (Version v1.0.0).

Motivation


According to this report youth disconnection although generally showing decreasing trends for the past 7 years, shows racial and ethnic disparities, where some groups are showing increased rates of disconnection.

So what does the term “youth disconnection” mean?

According to Measure of America (a nonpartisan project of the nonprofit Social Science Research Council that is focused on opportunity in the United States) disconnected youth are:

“young people between the ages of 16 and 24 who are neither working nor in school

They state that such disconnection hinders these individuals to aquire skills and create relationships necessary to have a sucessful adulthood.

They state that:

“people who experience a period of disconnection as young adults go on to earn less and are less likely to be employed, own a home, or report good health by the time they reach their thirties”

Disconnected youth are also referred to as opportunity youth, which has the added positive connotation that promoting such individuals can be beneficial not only for these individuals but also for their communties and for society.

We will expand beyond the Measure of America annual report to take a deeper look at differences of specific groups of youths. Identifying youths particularly at risk or disconnected, can help inform the design of targeted prevention and rengagement strategies.

This case study is motivated by this article:

Mendelson, T., Mmari, K., Blum, R. W., Catalano, R. F. & Brindis, C. D. Opportunity Youth: Insights and Opportunities for a Public Health Approach to Reengage Disconnected Teenagers and Young Adults. Public Health Rep 133, 54S-64S (2018).

This article describes strategies for prevention of disconnection and reengagement of discconnected youth and how such interventions could greatly positively impact opportunity youth for the entire trajectory of their lives and for future generations. It also points out that indeed their are disparities among different racial/ethnic groups.

Main Questions


Our main questions:

  1. How have youth disconnection rates in American youth changed since 2008?
  2. In particular, how has this changed for different gender and ethnic groups? Are any groups particularly disconnected?

Learning Objectives


In this case study, we will demonstrate how to import and wrangle data available in the Portable Document Format (PDF). We will especially focus on using packages and functions from the Tidyverse, such as dplyr, ggplot2. The tidyverse is a library of packages created by RStudio. While some students may be familiar with previous R programming packages, these packages make data science in R more legible and intuitive.

The skills, methods, and concepts that students will be familiar with by the end of this case study are:

Data science skills:

  1. Importing data from PDF files using the magick package
  2. Apply action verbs in dplyr for data wrangling
  3. How to pivot between “long” and “wide” datasets (tidyr)
  4. Joining together multiple datasets using dplyr
  5. How to create data visualizations with ggplot2 that are in a similar style to an existing image

Statistical concepts and methods:

  1. Implementation of the Mann-Kendall trend test
  2. Interpretation of the Mann-Kendall trend test


We will begin by loading the packages that we will need:

Package Use
here to easily load and save data
tidyverse for data science operations
pdftools to manage PDF documents
magick for image processing

The first time we use a function, we will use the :: to indicate which package we are using. Unless we have overlapping function names, this is not necessary, but we will include it here to be informative about where the functions we will use come from.

Context


So how does youth disconnection happen and what impact does it have?

There are many known risk factors, which have been identified in a variety of contexts (from family, friends, school, community, society) including:

  • poverty (disconnected youth are nearly twice as likely to live in poverty and receive Medicaid)
  • racial/ethnic disparities (findings suggest that these persist even when controlling for income)
  • residential environment (in 2016 while 11.7% was the national average, 24% of people age 16-24 in the rural South were disconnected)
  • poor academic performance
  • poor mental health
  • substance use disorders
  • parental unemployment
  • trauma exposure
  • association with socially deviant peers
  • school policies such as “one strike and you’re out” - which is a zero tolerance school expulsion policy and shown to increase dropouts and incarceration rates

These risk factors make it more likely for young people to miss out on education, training, and networking that can act as a foundation for a sucessful career.

There are also many known negative consequences associated with youth disconnection including but not limited to:

  • chronic unemployment
  • poverty
  • poor menthal health and poor general health (in a 2002 study - youths discoonected for 6 or more months were 3 times more likely to develop depression or other mental health disorder)
  • crimial behavior (in a 2002 study - youths discoonected for 6 or more months were 5 times more likely to have a criminal record)
  • incarceration
  • early mortality

Photo by Jon Tyson on Unsplash

Furthermore, in 2012 it was estimated that each disconnected youth costs taxpayers $250000 during a life time due to lost tax revenue and costs for social sercices, heath care and criminal justice.

Youth disconnection can be described as a continuum, as some youths will be disconnected for a brief time, while others are chronically disconnected. Additionally, while an individual who is out of school and work and also has poor support from the realtionships of others may be further disconnected than an individual who has social support.

Here is an illustration of risk factors, protective factors and the continuum of disconnection:

##### [source]

Strategies to mitigate youth disconnection

Many programs have identified useful strategies in rengaging disconnected youth or preventing discconection of youth.

generally speaking, most programs focus on reengagement strategies, however, prevention strategies are likely to be just as important.

Reserach suggests that active involvement with at risk youth from infancy and across multiple developmental stages through young adulthood whould be the most beneficial.

In fact, the quality of parental caregiving of infants age 6-24 months has actually been shown to be a predictor of high school dropout rates! Thus early interventions may be very important and consistent continual engagement may prevent further disconnection of youths.

Prevention strategies include:

See here and here for listings of programs dedicated to rengaging disconnected youth or preventing disconnection.

See here and here for particular examples.

The statistics used in this section came from this article.

Limitations


There are some important considerations regarding this data analysis to keep in mind:

  1. This data used in the Measure of America project reports from the is derived from American Community Survey(ASC) which excludes or underrepresents certain opportunity youth groups, such as youths in the juvenile justice system, youths in the foster care system, and homeless youths as the survey is conducted on households. Furthermore, youths who may be more disconnected for other reasons besides not being in work or school, such as dealing with the added challenge of being a teenage mother, or being abused is not available in this dataset. Thus, this data likely underestimates youth disconnection rates.

  2. Data about certain group intersections (meaning for example individuals of a particular gender and ethnicity) or particular groups in general such as specific ethnicities or gender or sexual identity groups such as LGBT (lesbian/gay/bisexual/transgender/queer and questioning) or nonbinary gender populations is unfortunately not available in the data used in this analysis and in most research about this topic. Luckily however, recent years of the ACS survey has more detailed infromation about a greater number of racial and ethnic groups and racial/ethnic intersections.

  3. The statistical procedures we are using may be overly simplistic. In all data analysis, we need to be wary about deriving meaning from the statistical procedures we use.

  4. Using image processing tools can be very helpful. The manner in which data is obtained with image processing tools is what we would describe as a black box process, a process with known inputs and outputs but unknown mechanics. Because we are unaware of how our outputs are generated from our inputs, we need to be wary of the output. With the small output we are creating in this case study, a visual inspection should suffice.

What are the data?


In this case study we will be using data related to youth disconnection from the two following reports from the Measure of America project:

Measure of America is a nonpartisan project of the nonprofit Social Science Research Council founded in 2007 to create easy-to-use yet methodologically sound tools for understanding well-being and opportunity in America. Through reports, interactive apps, and custom-built dashboards, Measure of America works with partners to breathe life into numbers, using data to identify areas of highest need, pinpoint levers for change, and track progress over time.

  1. Lewis, Kristen. Making the Connection: Transportation and Youth Disconnection . New York: Measure of America, Social Science Research Council, 2019. (Data up to 2017)

  1. : Lewis, Kristen. A Decade Undone: Youth Disconnection in the Age of Coronavirus. New York: Measure of America, Social Science Research Council, 2020. (Data up to 2018)

The data used in these reports comes from the American Community Survey(ASC), which is the largest survey conducted by the United States Census Bureau. The survey started in 2005 and collects data for 3.5 million households annually. Data is collected about ancestry, citizehsip, income, employment, disability among many other aspects. See here for more detailed information about the survey.

According to Wikipedia (https://en.wikipedia.org/wiki/American_Community_Survey){target="_blank"}:

Data is collected by internet, mail, telephone interviews and in-person interviews…About 95 percent of households across all response modes ultimately respond… ACS responses are confidential… and “immune from legal process”

It is a mandatory survey, it is governed by federal laws that could impose a fine of as much as $5,000 for refusing to participate.

We are particuarlly interesed in the following tables on the last page of the Measure of America 2019 report:

We are particuarlly interesed in the tables on the following pages from the Measure of America 2020 report:

Data Import


One way to import data from a pdf is to use the pdf_text() function of the pdftools package. The here() function of the here package can allow us to specify where the document that we want to import is located easily, starting from the directory where a .Rproj file is located. In this case, we will import the Making_the_Connection.pdf in the docs directory. Note this is the case if you pull the repository from github.

We can take a look at the output for the page with our table of interests by simpy using brackets [] around the page number. The page we are interested in (athough called 39 in the report) is the 44th page, which looks like this:

[1] "Youth Disconnection by Gender and by Race and Ethnicity\n                                                                                                                                               I NDI CATOR TA BLE S\n                                DISCONNECTED YOUTH\nMAJOR RACIAL AND                 RATE (% ages 16–24)                                  2017          CHANGE IN RATE\nETHNIC GROUPS            2008   2010       2012           2014     2016        (%)           (#)     2010–2017 (%)\nUnited States            12.6   14.7       14.1           13.2     11.7        11.5     4,501,800       -22.1\nMale                     12.3   15.2       14.5           13.3     12.1        11.8     2,382,500       -22.5\nFemale                   12.9   14.1       13.7           13.0     11.2        11.1     2,119,400       -21.7\nASIAN                    7.1     8.5       7.8            7.9       6.6        6.6      145,600         -21.7\nAsian Male               6.3     8.3          7.4         7.2       6.7        6.5       73,000         -21.4\nAsian Female             7.9     8.6          8.1         8.6       6.6        6.7       72,600         -22.0\nWHITE                    9.7    11.7       11.2           10.8      9.7        9.4      1,961,700       -20.1\nWhite Male               9.5    12.3       11.5           10.8    10.0         9.6      1,031,200       -22.4\nWhite Female             10.0   11.1       10.8           10.7      9.4        9.1       930,600        -17.4\nLATINO                   16.7   18.5       17.3           15.2     13.7        13.2     1,157,300       -28.7\nLatino Male              13.6   16.8       16.0           14.0     12.6        12.4      562,600        -26.0\nLatina Female            20.2   20.3       18.8           16.5     14.8        13.9      594,700        -31.5\nBLACK                    20.4   22.5       22.4           20.6     17.2        17.9     999,700         -20.6\nBlack Male               23.7   26.0       25.6           23.5     20.1        20.8      591,600        -19.8\nBlack Female             17.0   19.0       19.3           17.6     14.2        14.8      408,000        -22.1\nNATIVE AMERICAN          24.4   28.8       27.0           26.3     25.8        23.9      67,700         -17.1\nNative American Male     25.0   30.9       28.0           26.9     28.1        23.3      33,200         -24.5\nNative American Female   23.9   26.7       25.9           25.6     23.4        24.5      34,500         -8.4\n                                       2017                                                                            2017\n ASIAN SUBGROUPS                (%)                 (#)          LATINO SUBGROUPS                               (%)             (#)\n United States                  11.5       4,501,800\n Male                           11.8          2,382,500          LATINO                                         13.2          1,157,300\n Female                         11.1          2,119,400          Latino Male                                    12.4           562,600\n ASIAN                          6.6           145,600            Latina Female                                  13.9           594,700\n Asian Male                     6.5            73,000            SOUTH AMERICAN                                 8.4            37,600\n Asian Female                   6.7            72,600            South American Male                            9.1            20,400\n CHINESE                        4.3            23,800            South American Female                          7.7            17,200\n Chinese Male                   4.7            12,700            CENTRAL AMERICAN                               12.0           93,100\n Chinese Female                 3.9            11,100            Central American Male                          9.3            37,900\n VIETNAMESE                     5.5            13,500            Central American Female                        15.0           55,200\n Vietnamese Male                7.5             9,300\n                                                                 MEXICAN                                        13.3          762,400\n Vietnamese Female              3.4             4,200\n                                                                 Mexican Male                                   12.2           358,200\nINDIAN                          5.9            22,300\n                                                                 Mexican Female                                 14.4           404,200\nIndian Male                     4.1             8,000            OTHER LATINO                                   13.6           44,800\nIndian Female                   7.8            14,300\n                                                                 Other Latino Male                              15.3           27,600\n PAKISTANI                      6.4             4,900\n                                                                 Other Latina Female                            11.5           17,300\n Pakistani Male\n                                                                 PUERTO RICAN, DOMINICAN, CUBAN                 15.1          211,200\n Pakistani Female\n                                                                 PR, DR, Cuban Female                           15.7           114,500\n KOREAN                         6.5            11,200\n                                                                 PR, DR, Cuban Female                           14.4           96,600\n Korean Male                    8.0             6,900\n Korean Female                  5.0             4,200\n                                                                 NOTE: Blank cells indicate the estimate is unreliable\n TWO OR MORE                    6.6             4,000\n Two or More Male\n Two or More Female\nFILIPINO                        7.3            23,400\nFilipino Male                   6.5            10,800\nFilipino Female                 8.1            12,700\nHMONG                           14.0            8,300\nHmong Male                      18.6            5,700\nHmong Female\nMAKING THE CONNECTION | Transportation and Youth Disconnection                                                                            39\n"

From the output, it’s clear that a relatively large amount of manipulation will be required to wrangle this data. If you are interested in learning more about this method, please see this case study and this case study.

While not impossible, using the pdftools package in this scenario will require some advanced data wrangling.

While our output may be reproducible, this process may be too time consuming.

Fortunately, there is another way we can proceed to wrangle the data.

We will demonstrate how to produce reproducible tables with image processing software in R using a package called magick which allows for the extraction of text from images.

For demonstrative purposes, we will import two sets of data. The first set of data will be used to highlight common errors that the image processing software may produce. The second set of data will be used to demonstrate how to circumvent these errors and produce reproducible datasets efficiently.

Importing with magick

We will now import the data using the magick package which allows for the improtation of images.

First we will take a screenshot of the top part of the gender, race, and ethnicity table on the last page of the 2019 Measure of America Report.

We can show what this file looks like in this rendered rmarkdown website by using the include_graphics() function of the knitr package.

Now, we will use the image_read() function of the magick package to import this image.

We can then use teh image_info() function to make sure that the import worked and to get information about the size, format and color of the image.

# A tibble: 1 x 7
  format width height colorspace matte filesize density
  <chr>  <int>  <int> <chr>      <lgl>    <int> <chr>  
1 PNG      997    711 sRGB       TRUE    164964 72x72  

Now let’s take a look at our image in R! Now that we have imported it to see this image, we simply need to type the name of the image.

Nice!

We will demonstrate in a bit that the top part of the table causes issues when extracting the text from this image. So now we will take a screen shot without the top part of the table and do the same process.

Let’s import one more image just for fun. Here we will import an image directly from a URL.

Now we will use the image_ocr() function of the magick package to extract the text from the OCS logo image. This function uses the tesseract package which has tools for optical character recognition (OCR), hence the ocr in the function name. This allows the function to identify text in images. These OCR tools have often been developed using machine learning in which an algorithm was trained on images with and without text to “learn” to recognize text. See here to learn more about how OCR works.

[1] "ggplot2\n"

Awesome! We were able to extract text from this hex sticker!

One thing to keep in mind is that this doesn’t always work. Unusual font, angles text, or particular colors can be difficult for the OCR to recoginize.

Here is an example that does not work with the current version of magick:

[1] ""

This is likely do to the background on this particular hex sticker.

Data Exploration and Wrangling


Now let’s try extracting the text from our image files.

The first image we imported looks like this.

Now we will extract the text!

[1] "Youth Disconnection by Gender and by Race and Ethnicity\nbyte) ee\nMAJOR RACIAL AND Cr erent) ed Nas\nUnited States 126 147 14.1 13.21.7115 4,501,800 22.1\nMale 12.3 15.2 14.5 13.3 12.1 11.8 2,382,500 -22.5\nFemale 12.9 14.1 13.7 13.0 11.2 11.1 2,119,400 -21.7\nASIAN 71 85 78 19 66 66 145,600 -21.7\nAsian Male 6.3 8.3 74 7.2 6.7 65 73,000 -21.4\nAsian Female 7.9 8.6 8.1 8.6 6.6 6.7 72,600 -22.0\nWHITE 97 210897 9.4 1,961,700 -20.1\nWhite Male 95 12.3 11.5 10.8 10.0 9.6 1,031,200 -22.4\nWhite Female 10.0 11.1 10.8 10.7 9.4 91 930,600 -17.4\nLATINO 167-185 17.3 15.2 13.7 =~ 138.2_—_—‘1,157,300 -28.7\nLatino Male 13.6 16.8 16.0 14.0 12.6 12.4 562,600 -26.0\nLatina Female 20.2 20.3 18.8 16.5 14.8 13.9 594,700 -31.5\nBLACK 20.4 225 224 206 17.2 17.9 999,700 -20.6\nBlack Male 23.7 26.0 25.6 23.5 20.1 20.8 591,600 -19.8\nBlack Female 17.0 19.0 19.3 17.6 14.2 14.8 408,000 -22.1\nNATIVE AMERICAN 264 288 27.0 23 28 23.9 67,700 -17.1\nNative American Male 25.0 30.9 28.0 26.9 28.1 23.3 33,200 -24.5\nNative American Female 23.9 26.7 25.9 25.6 23.4 24.5 34,500 -B.4\n"

This looks like it worked fairly well!

You may notice that there are lots of \n values in the text from our image. These are newline characters, which denote the end of a line of text and the start of a new line of text.

We can use the str_split() function of the stringr package to split based on the \n characters in the output. We will then unlist the output using the base R unlist() function. By base, we mean that the function it is loaded automatically in an R session. Finally we will use the as_tibble() function of the tibble package to convert the data into tibble format, which is the tidyverse version of a data frame. This will allow us to see the values in the table much better.

To do all of these sequential steps efficiently we will use a method called piping.


Click here if you are unfamiliar with piping in R, which uses this %>% operator

By piping we mean using the %>% pipe operator which is accessible after loading the tidyverse or several of the packages within the tidyverse like dplyr because they load the magrittr package. This allows us to perform multiple sequential steps on one data input.

# A tibble: 22 x 1
   value                                                  
   <chr>                                                  
 1 Youth Disconnection by Gender and by Race and Ethnicity
 2 byte) ee                                               
 3 MAJOR RACIAL AND Cr erent) ed Nas                      
 4 United States 126 147 14.1 13.21.7115 4,501,800 22.1   
 5 Male 12.3 15.2 14.5 13.3 12.1 11.8 2,382,500 -22.5     
 6 Female 12.9 14.1 13.7 13.0 11.2 11.1 2,119,400 -21.7   
 7 ASIAN 71 85 78 19 66 66 145,600 -21.7                  
 8 Asian Male 6.3 8.3 74 7.2 6.7 65 73,000 -21.4          
 9 Asian Female 7.9 8.6 8.1 8.6 6.6 6.7 72,600 -22.0      
10 WHITE 97 210897 9.4 1,961,700 -20.1                    
# … with 12 more rows

OK, not bad, the top looks a bit strange but the rest of the table looks fairly good, but there are some rows that look particularly strange like the row that starts with LATINO, or you may notice that the row for Native American females ends with -B.4:

[[1]]
[1] "LATINO"              "167-185"             "17.3"               
[4] "15.2"                "13.7"                "=~"                 
[7] "138.2_—_—‘1,157,300" "-28.7"              
[[1]]
 [1] "Native"   "American" "Female"   "23.9"     "26.7"     "25.9"    
 [7] "25.6"     "23.4"     "24.5"     "34,500"   "-B.4"    

Data wrangling is not an exact science. The approaches we can take are extremely dependent on the data. We can exploit patterns in the data to render the output we desire.

The first few lines of our table have quite a bit of special formatting, there are different font colors and backgrounds.As we saw previously, this can sometimes cause issues. So now we will try use the cropped version of the image.

# A tibble: 19 x 1
   value                                                             
   <chr>                                                             
 1 "United States 12.6 14.7 14.1 13.2 11.7 11.5 4,501,800 -22.1"     
 2 "Male 12.3 15.2 14.5 13.3 12.1 11.8 2,382,500 -22.5"              
 3 "Female 12.9 14.1 13.7 13.0 11.2 11.1 2,119,400 -21.7"            
 4 "ASIAN 71 8.5 7.8 79 6.6 6.6 145,600 -21.7"                       
 5 "Asian Male 63 8.3 74 7.2 67 6.5 73,000 -21.4"                    
 6 "Asian Female 79 8.6 8.1 8.6 6.6 67 72,600 -22.0"                 
 7 "WHITE 9.7 11.7 11.2 10.8 9.7 94 1,961,700 -20.1"                 
 8 "White Male 95 12.3 11.5 10.8 10.0 9.6 1,031,200 -22.4"           
 9 "White Female 10.0 11.1 10.8 10.7 9.4 9.1 930,600 -17.4"          
10 "LATINO 16.7 18.5 17.3 15.2 13.7 13.2 1,157,300 -28.7"            
11 "Latino Male 13.6 16.8 16.0 14.0 12.6 12.4 562,600 -26.0"         
12 "Latina Female 20.2 20.3 18.8 16.5 14.8 13.9 594,700 -31.5"       
13 "BLACK 20.4 22.5 22.4 20.6 17.2 17.9 999,700 -20.6"               
14 "Black Male 23.7 26.0 25.6 23.5 20.1 20.8 591,600 -19.8"          
15 "Black Female 17.0 19.0 19.3 17.6 14.2 14.8 408,000 -22.1"        
16 "NATIVE AMERICAN 24.4 28.8 27.0 26.3 25.8 23.9 67,700 -17.1"      
17 "Native American Male 25.0 30.9 28.0 26.9 28.1 23.3 33,200 -24.5" 
18 "Native American Female 23.9 26.7 25.9 25.6 23.4 24.5 34,500 -8.4"
19 ""                                                                

This looks much better!

It’s important to look very carefully at the text. Now although we no longer have the previous issues. There are some values missing a decimal place. For example the row that starts with ASIAN, the first value is missing a decimal place.

Now we will try using separtate images of just the names and the data. We only want data about the percent each year, so we can exclude the last few columns in this image. The larger an image is and the better the resolution, the more likely that the text will be extracted correctly.

Now let’s try extracting the text from these images and separating the rows by the newline character \n.

Question Opportunity

Can you recall the commands to do this?

Click here to reveal the code.

# A tibble: 33 x 1
   value          
   <chr>          
 1 "United States"
 2 ""             
 3 "Male"         
 4 ""             
 5 "Female"       
 6 ""             
 7 "ASIAN"        
 8 ""             
 9 "Asian Male"   
10 ""             
# … with 23 more rows
# A tibble: 19 x 1
   value                          
   <chr>                          
 1 "12.6 14.7 14.1 13.2 11.7 11.5"
 2 "12.3 15.2 14.5 13.3 12.1 11.8"
 3 "12.9 14.1 13.7 13.0 11.2 11.1"
 4 "7.1 8.5 7.8 79 6.6 6.6"       
 5 "6.3 8.3 74 7.2 6.7 6.5"       
 6 "7.9 8.6 8.1 8.6 6.6 6.7"      
 7 "9.7 11.7 11.2 10.8 9.7 9.4"   
 8 "9.5 12.3 11.5 10.8 10.0 9.6"  
 9 "10.0 11.1 10.8 10.7 9.4 9.1"  
10 "16.7 18.5 17.3 15.2 13.7 13.2"
11 "13.6 16.8 16.0 14.0 12.6 12.4"
12 "20.2 20.3 18.8 16.5 14.8 13.9"
13 "20.4 22.5 22.4 20.6 17.2 17.9"
14 "23.7 26.0 25.6 23.5 20.1 20.8"
15 "17.0 19.0 19.3 17.6 14.2 14.8"
16 "24.4 28.8 27.0 26.3 25.8 23.9"
17 "25.0 30.9 28.0 26.9 28.1 23.3"
18 "23.9 26.7 25.9 25.6 23.4 24.5"
19 ""                             

OK! this looks pretty good! The only issue is we have some extra rows in between each row in the ethnic_groups object.

We can remove these extra rows using the filter() function of the dplyr package to exclude all rows that are just an empty string and thus a set of quotes "" using the not equals operator !=.

We are also going to use a special pipe operator from the magrittr package called the compound assignment pipe-operator or sometimes the double pipe operator.

This allows us to use the ethnic_groups as our input and reassign it at the end after all the steps have been performed.

# A tibble: 18 x 1
   value                 
   <chr>                 
 1 United States         
 2 Male                  
 3 Female                
 4 ASIAN                 
 5 Asian Male            
 6 Asian Female          
 7 WHITE                 
 8 White Male            
 9 White Female          
10 LATINO                
11 Latino Male           
12 Latina Female         
13 BLACK                 
14 Black Male            
15 Black Female          
16 NATIVE AMERICAN       
17 Native American Male  
18 Native American Female

Let’s also get rid of the all caps for the major categories. We can convert the words to only capitalize the first letter using the str_to_title() function of the stringr package.

# A tibble: 18 x 1
   value                 
   <chr>                 
 1 United States         
 2 Male                  
 3 Female                
 4 Asian                 
 5 Asian Male            
 6 Asian Female          
 7 White                 
 8 White Male            
 9 White Female          
10 Latino                
11 Latino Male           
12 Latina Female         
13 Black                 
14 Black Male            
15 Black Female          
16 Native American       
17 Native American Male  
18 Native American Female

Nice! that looks better.

For the year data we would like to try splitting the strings for each row into different columns based on a space. Currently all the data is listed in one column called value.

We can use the separate function of the tidyr pacakge to do this. This will allow us to not only split the rows by spaces, but also to create column names.

There are three important arguments for the seperate() function:
- col - this specifies what column you are separating
- into - this specifies the names of the new columns you are creating
- sep - this specifies what character string to look for to separate by

# A tibble: 19 x 6
   `2008` `2010` `2012` `2014` `2016` `2017`
   <chr>  <chr>  <chr>  <chr>  <chr>  <chr> 
 1 "12.6" 14.7   14.1   13.2   11.7   11.5  
 2 "12.3" 15.2   14.5   13.3   12.1   11.8  
 3 "12.9" 14.1   13.7   13.0   11.2   11.1  
 4 "7.1"  8.5    7.8    79     6.6    6.6   
 5 "6.3"  8.3    74     7.2    6.7    6.5   
 6 "7.9"  8.6    8.1    8.6    6.6    6.7   
 7 "9.7"  11.7   11.2   10.8   9.7    9.4   
 8 "9.5"  12.3   11.5   10.8   10.0   9.6   
 9 "10.0" 11.1   10.8   10.7   9.4    9.1   
10 "16.7" 18.5   17.3   15.2   13.7   13.2  
11 "13.6" 16.8   16.0   14.0   12.6   12.4  
12 "20.2" 20.3   18.8   16.5   14.8   13.9  
13 "20.4" 22.5   22.4   20.6   17.2   17.9  
14 "23.7" 26.0   25.6   23.5   20.1   20.8  
15 "17.0" 19.0   19.3   17.6   14.2   14.8  
16 "24.4" 28.8   27.0   26.3   25.8   23.9  
17 "25.0" 30.9   28.0   26.9   28.1   23.3  
18 "23.9" 26.7   25.9   25.6   23.4   24.5  
19 ""     <NA>   <NA>   <NA>   <NA>   <NA>  

Looks pretty good!

We appear to have an empty row at the very end. Since all the values are NA, we can use the drop_na() function of the tidyr package to remove it.

# A tibble: 18 x 6
   `2008` `2010` `2012` `2014` `2016` `2017`
   <chr>  <chr>  <chr>  <chr>  <chr>  <chr> 
 1 12.6   14.7   14.1   13.2   11.7   11.5  
 2 12.3   15.2   14.5   13.3   12.1   11.8  
 3 12.9   14.1   13.7   13.0   11.2   11.1  
 4 7.1    8.5    7.8    79     6.6    6.6   
 5 6.3    8.3    74     7.2    6.7    6.5   
 6 7.9    8.6    8.1    8.6    6.6    6.7   
 7 9.7    11.7   11.2   10.8   9.7    9.4   
 8 9.5    12.3   11.5   10.8   10.0   9.6   
 9 10.0   11.1   10.8   10.7   9.4    9.1   
10 16.7   18.5   17.3   15.2   13.7   13.2  
11 13.6   16.8   16.0   14.0   12.6   12.4  
12 20.2   20.3   18.8   16.5   14.8   13.9  
13 20.4   22.5   22.4   20.6   17.2   17.9  
14 23.7   26.0   25.6   23.5   20.1   20.8  
15 17.0   19.0   19.3   17.6   14.2   14.8  
16 24.4   28.8   27.0   26.3   25.8   23.9  
17 25.0   30.9   28.0   26.9   28.1   23.3  
18 23.9   26.7   25.9   25.6   23.4   24.5  

Great! Now we only have 18 rows.

Now let’s make these values numeric. Currently we can tell that they are character strings based on the <char> values listed under each column name.

Click here for an explanation of what a character string is

There are several classes of data in R programming. Character is one of these classes. A character string is an individual data value made up of characters. This can be a paragraph, like the legend for the table, or it can be a single letter or number like the letter "a" or the number "3". If data are of class character, than the numeric values will not be processed like a numeric value in a mathematical sense. If you want your numeric values to be interpreted that way, they need to be converted to a numeric class. The options typically used are integer (which has no decimal place) and double precision (which has a decimal place).

To convert our values to be numeric we can use the base as.numeric() function. To apply this to all the rows in years we can use the map_df() function of the purrr package. The map() would also work, however, the special map_df() function keeps the output in the same tibble format. A . is necessary to tell the map_df() function to apply the as_numeric() function to the values of the years tibble.

# A tibble: 18 x 6
   `2008` `2010` `2012` `2014` `2016` `2017`
    <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>
 1   12.6   14.7   14.1   13.2   11.7   11.5
 2   12.3   15.2   14.5   13.3   12.1   11.8
 3   12.9   14.1   13.7   13     11.2   11.1
 4    7.1    8.5    7.8   79      6.6    6.6
 5    6.3    8.3   74      7.2    6.7    6.5
 6    7.9    8.6    8.1    8.6    6.6    6.7
 7    9.7   11.7   11.2   10.8    9.7    9.4
 8    9.5   12.3   11.5   10.8   10      9.6
 9   10     11.1   10.8   10.7    9.4    9.1
10   16.7   18.5   17.3   15.2   13.7   13.2
11   13.6   16.8   16     14     12.6   12.4
12   20.2   20.3   18.8   16.5   14.8   13.9
13   20.4   22.5   22.4   20.6   17.2   17.9
14   23.7   26     25.6   23.5   20.1   20.8
15   17     19     19.3   17.6   14.2   14.8
16   24.4   28.8   27     26.3   25.8   23.9
17   25     30.9   28     26.9   28.1   23.3
18   23.9   26.7   25.9   25.6   23.4   24.5

We are now ready to put the ethnic_groups and years objects together.

We can do so using the col_bind function.

To rename the column name of the value variable of the disconnection tibble we will use the rename() function of the dplyr package.

The new name needs to be listed first before the old name.

From Michael:

We split the dataframe in two: a labels section and a “data” section containing the information we are interested in.

In the first half, we remove all digits and punctuation to ensure that we are left with character labels.

In the second-half, remove commas and periods, converting the resulting string character class to numeric and selectively multiplying columns to reintroduce the decimal point correctly.

We combine the two sections of data to create our dataframe, removing and then adding column names.

We remove columns with information we don’t need and use the commmon pattern in the column names to convert the data into long/narrow format.

We use the dplyr::case_when() and stringr::str_detect() function to detect patterns and create an separate column with gender and race information.

The two columns created contain TRUE/FALSE statements. These are then used to create a third column that will allow us to separate the data by its summary level.

# A tibble: 114 x 3
   Group         Year  Rate
   <chr>        <dbl> <dbl>
 1 UnitedStates  2008  12.6
 2 UnitedStates  2010  14.7
 3 UnitedStates  2012  14.1
 4 UnitedStates  2014  13.2
 5 UnitedStates  2016  11.7
 6 UnitedStates  2017  11.5
 7 Male          2008  12.3
 8 Male          2010  15.2
 9 Male          2012  14.5
10 Male          2014  13.3
# … with 104 more rows

The columns of character class currently contain upper and lower case characters. We want to ensure that we use a cases consistently to ensure that there are no errors driven by case-sensitive function downstream.

To do this, we use the base::to_upper() function. This function makes all characters uppercase.

Finally, we homogenize the labels assigned for certain groups, fill in missing (NA) values with a string, and remove columns we no longer need from the dataframe.

We can repeat this process for the other two tables listed on page 39.

Let’s look at the table without the special formatting.

As you can see, there are empty spaces. According to the PDF, these spaces are empty to denote that the estimates are unreliable.

This may cause problems. Whitespace must be handled differently. We may not want to process the entire image for this reason.

Instead, we can use separate images to ensure a simpler process like that above.

We read the three images.

# A tibble: 1 x 7
  format width height colorspace matte filesize density
  <chr>  <int>  <int> <chr>      <lgl>    <int> <chr>  
1 PNG      757    687 sRGB       TRUE     95660 72x72  
# A tibble: 1 x 7
  format width height colorspace matte filesize density
  <chr>  <int>  <int> <chr>      <lgl>    <int> <chr>  
1 PNG      751    177 sRGB       TRUE     28913 72x72  
# A tibble: 1 x 7
  format width height colorspace matte filesize density
  <chr>  <int>  <int> <chr>      <lgl>    <int> <chr>  
1 PNG      760    216 sRGB       TRUE     33402 72x72  

The images look like this.

We save the text from the images into objects.

We process these objects separately. Note that we use a very similar process to that employed in the wrangling of the previous table.

We then combine the objects with the dplyr::bind_rows() function.

The process is now very similar to the previous table.

MICHAEL ONTIVEROS

I used base R to remove the first three rows of a dataframe in the following chunk. I am not aware of a tidyverse solution for this; I am sure one exists.

Rows: 25
Columns: 5
$ Group    <chr> "UnitedStates", "Male", "Female", "ASIAN", "AsianMale", "Asi…
$ Rate     <dbl> 11.5, 11.8, 11.1, 6.6, 6.5, 6.7, 4.3, 4.7, 3.9, 5.5, 7.5, 3.…
$ Year     <dbl> 2017, 2017, 2017, 2017, 2017, 2017, 2017, 2017, 2017, 2017, …
$ Gender   <lgl> NA, FALSE, TRUE, NA, FALSE, TRUE, NA, FALSE, TRUE, NA, FALSE…
$ Subgroup <chr> "UnitedStates", NA, NA, NA, NA, NA, "CHINESE", "Chinese", "C…
Rows: 22
Columns: 6
$ Group    <chr> "ASIAN", "AsianMale", "AsianFemale", "CHINESE", "ChineseMale…
$ Rate     <dbl> 6.6, 6.5, 6.7, 4.3, 4.7, 3.9, 5.5, 7.5, 3.4, 5.9, 4.1, 7.8, …
$ Year     <dbl> 2017, 2017, 2017, 2017, 2017, 2017, 2017, 2017, 2017, 2017, …
$ Gender   <lgl> NA, FALSE, TRUE, NA, FALSE, TRUE, NA, FALSE, TRUE, NA, FALSE…
$ Subgroup <chr> NA, NA, NA, "CHINESE", "Chinese", "Chinese", "VIETNAMESE", "…
$ Type     <chr> "Asian Total", "Gender Total", "Gender Total", "Subgroup Tot…

Note that we took a process that had successfully worked for us and modified it slightly for separate, similarly-sourced data.

This is a common approach in data science. Often, the duration of the wrangling process can limit the depth of an analysis for practical reasons. Using tried methods can help reduce the time needed to wrangle data and allow time for other parts of an analysis.

Let’s add the 2018 data for this group.

We import the image.

As you can see, we have repeated newlines (\n). We can remove these with some simplex regex.

We proceed, making slight modifications to the process as needed.

The bold font appears to have caused a typos.

# A tibble: 17 x 1
   value                
   <chr>                
 1 CHINESE  41  23300   
 2 Men  45  12500       
 3 Women  37 10800      
 4 INDIAN  B44  21800   
 5 Men  47  10400       
 6 Women  61  11300     
 7 KOREAN  55  9000     
 8 Men  56  4700        
 9 Women  54  4300      
10 VIETNAMESE  63  15300
11 Men  76  9000        
12 Women  50  6400      
13 FILIPINO  68  20800  
14 Men  63  10000       
15 Women74  10800       
16 HMONG102  5300       
17 CAMBODIAN 138  4200  

We fix the typos.

# A tibble: 17 x 1
   value                
   <chr>                
 1 CHINESE  41  23300   
 2 Men  45  12500       
 3 Women  37 10800      
 4 INDIAN 54 21800      
 5 Men  47  10400       
 6 Women  61  11300     
 7 KOREAN  55  9000     
 8 Men  56  4700        
 9 Women  54  4300      
10 VIETNAMESE  63  15300
11 Men  76  9000        
12 Women  50  6400      
13 FILIPINO  68  20800  
14 Men  63  10000       
15 Women 74  10800      
16 HMONG 102  5300      
17 CAMBODIAN 138  4200  

We then continue as we would normally.

[1] 17
Rows: 17
Columns: 6
$ Group    <chr> "CHINESE", "Men", "Women", "INDIAN", "Men", "Women", "KOREAN…
$ Rate     <dbl> 4.1, 4.5, 3.7, 5.4, 4.7, 6.1, 5.5, 5.6, 5.4, 6.3, 7.6, 5.0, …
$ Year     <dbl> 2018, 2018, 2018, 2018, 2018, 2018, 2018, 2018, 2018, 2018, …
$ Gender   <lgl> NA, FALSE, TRUE, NA, FALSE, TRUE, NA, FALSE, TRUE, NA, FALSE…
$ Subgroup <chr> "CHINESE", "CHINESE", "CHINESE", "INDIAN", "INDIAN", "INDIAN…
$ Type     <chr> "Subgroup Total", "Subgroup Total", "Subgroup Total", "Subgr…

The dataframe we produced does not contain totals.

# A tibble: 17 x 5
    Rate  Year Gender Subgroup   Type          
   <dbl> <dbl> <chr>  <chr>      <chr>         
 1   4.1  2018 ALL    CHINESE    SUBGROUP TOTAL
 2   4.5  2018 MALE   CHINESE    SUBGROUP TOTAL
 3   3.7  2018 FEMALE CHINESE    SUBGROUP TOTAL
 4   5.4  2018 ALL    INDIAN     SUBGROUP TOTAL
 5   4.7  2018 MALE   INDIAN     SUBGROUP TOTAL
 6   6.1  2018 FEMALE INDIAN     SUBGROUP TOTAL
 7   5.5  2018 ALL    KOREAN     SUBGROUP TOTAL
 8   5.6  2018 MALE   KOREAN     SUBGROUP TOTAL
 9   5.4  2018 FEMALE KOREAN     SUBGROUP TOTAL
10   6.3  2018 ALL    VIETNAMESE SUBGROUP TOTAL
11   7.6  2018 MALE   VIETNAMESE SUBGROUP TOTAL
12   5    2018 FEMALE VIETNAMESE SUBGROUP TOTAL
13   6.8  2018 ALL    FILIPINO   SUBGROUP TOTAL
14   6.3  2018 MALE   FILIPINO   SUBGROUP TOTAL
15   7.4  2018 FEMALE FILIPINO   SUBGROUP TOTAL
16  10.2  2018 ALL    HMONG      SUBGROUP TOTAL
17  13.8  2018 ALL    CAMBODIAN  SUBGROUP TOTAL

We can find these totals in the PDF directly and create rows as needed

We load the PDF.

We add the rows.

We repeat this process again for Latino/a subgroups.

The table, without the special formatting, looks like this.

There are no whitespaces in this table.

We proceed using what we’ve learned while wrangling the first two tables.

# A tibble: 17 x 1
   value                              
   <chr>                              
 1 LATINO 13.2 1,157,300              
 2 Latino Male 12.4 562,600           
 3 Latina Female 13.9 594,700         
 4 SOUTH AMERICAN 8.4 37,600          
 5 South American Male 9.1 20,400     
 6 South American Female 17 17,200    
 7 CENTRAL AMERICAN 12.0 93,100       
 8 Central American Male 9.3 37,900   
 9 Central American Female 15.0 55,200
10 MEXICAN 13.3 762,400               
11 Mexican Male 12.2 358,200          
12 Mexican Female 14.4 404,200        
13 OTHER LATINO 13.6 44,800           
14 Other Latino Male 15.3 27,600      
15 Other Latina Female 11.5 17,300    
16 PR, DR, Cuban Female 15.7 114,500  
17 PR, DR, Cuban Female 14.4 96,600   

We are often presented with scenarios where stand-alone approaches are difficult or time-consuming.

It is always best to document the steps take to respond to these scenarios. Wrangling this third table is a prime example of this.

We are missing a row. Let’s manually add the row.

We can now proceed as we did with the previous tables.

If we look at the last few rows, we see that there is a typo. There are two female groups.

# A tibble: 6 x 3
  Group              Rate N_2017
  <chr>             <dbl>  <dbl>
1 OTHERLATINO        13.6  44800
2 OtherLatinoMale    15.3  27600
3 OtherLatinaFemale  11.5  17300
4 PRDRCubanFemale    15.7 114500
5 PRDRCubanFemale    14.4  96600
6 PRDRCuban          15.1 211200

Sometimes when wrangling text data, we will come across a typo. We need to determine how to respond to the typo and make note of it. It’s often best to consult a secondary source to confirm that changes made are accurate.

For the purposes of this case study, we will assume that the first of the two rows represents male disconnection rates in the Latino/a subgroup; this would be consistent with the ordering of genders in the previous subgroups.

Let’s make the correction to the typo.

It looks like we’ve succesfully corrected the typo.

# A tibble: 6 x 3
  Group              Rate N_2017
  <chr>             <dbl>  <dbl>
1 OTHERLATINO        13.6  44800
2 OtherLatinoMale    15.3  27600
3 OtherLatinaFemale  11.5  17300
4 PRDRCubanMale      15.7 114500
5 PRDRCubanFemale    14.4  96600
6 PRDRCuban          15.1 211200

We can continue with the process we’ve developed now that we have made the correction.

Rows: 18
Columns: 5
$ Group    <chr> "LATINO", "LatinoMale", "LatinaFemale", "SOUTHAMERICAN", "So…
$ Rate     <dbl> 13.2, 12.4, 13.9, 8.4, 9.1, 1.7, 12.0, 9.3, 15.0, 13.3, 12.2…
$ Year     <dbl> 2017, 2017, 2017, 2017, 2017, 2017, 2017, 2017, 2017, 2017, …
$ Gender   <lgl> NA, FALSE, TRUE, NA, FALSE, TRUE, NA, FALSE, TRUE, NA, FALSE…
$ Subgroup <chr> NA, NA, NA, "SOUTHAMERICAN", "SouthAmerican", "SouthAmerican…
Rows: 18
Columns: 6
$ Group    <chr> "LATINO", "LatinoMale", "LatinaFemale", "SOUTHAMERICAN", "So…
$ Rate     <dbl> 13.2, 12.4, 13.9, 8.4, 9.1, 1.7, 12.0, 9.3, 15.0, 13.3, 12.2…
$ Year     <dbl> 2017, 2017, 2017, 2017, 2017, 2017, 2017, 2017, 2017, 2017, …
$ Gender   <lgl> NA, FALSE, TRUE, NA, FALSE, TRUE, NA, FALSE, TRUE, NA, FALSE…
$ Subgroup <chr> NA, NA, NA, "SOUTHAMERICAN", "SouthAmerican", "SouthAmerican…
$ Type     <chr> "Latino/a Total", "Gender Total", "Gender Total", "Subgroup …

Let’s add the 2018 data to this dataframe.

We import the image.

As you can see, we have repeated newlines (\n). We can remove these with some simplex regex.

We proceed, making slight modifications to the process as needed.

[1] 12
Rows: 12
Columns: 6
$ Group    <chr> "SOUTHAMERICAN", "Men", "Women", "MEXICAN", "Men", "Women", …
$ Rate     <dbl> 8.0, 7.5, 8.6, 12.9, 12.0, 13.8, 13.7, 14.9, 12.4, 13.7, 11.…
$ Year     <dbl> 2018, 2018, 2018, 2018, 2018, 2018, 2018, 2018, 2018, 2018, …
$ Gender   <lgl> NA, FALSE, TRUE, NA, FALSE, TRUE, NA, FALSE, TRUE, NA, FALSE…
$ Subgroup <chr> "SOUTHAMERICAN", "SOUTHAMERICAN", "SOUTHAMERICAN", "MEXICAN"…
$ Type     <chr> "Subgroup Total", "Subgroup Total", "Subgroup Total", "Subgr…

We load the PDF.

We add the rows.

We add the 2018 data to the dataframe

Map

We will use multiple images to import the data on page 36 to produce maps.

MICHAEL ONTIVEROS

This code is not complete. If there is time, we will return to it! Magick is having trouble with quadrant 1 and 4. I could not figure out why.

Data Analysis


Repeated Cross-sectional Data

We have pooled (repeated) cross-sectional data.

This is data produced from repeated measurement of a population over time.

It is often infeasible to collect data for an entire population at once. However, we can still obtain meaningful measures using a random sample of the population.

At specific time-points, data is collected from a sample of the population. The individuals in each sample are not necessarily the same individuals. This separates pooled cross-sectional data from panel data, which is longitudinal data from repeated measurement of the same people.

By sampling from a population at multiple time points, we can generate population level statistics. Although these statistics have some random error, they can provide insight into how the measure variable is changing in a population over time.

We can accomplish this by plotting the measured values over time. Sometimes, however, the trend isn’t exactly clear. Fortunately, there are statistical methods to resolve this issue.

The Mann-Kendall trend test—a variation of the Kendall rank correlation coefficient—tests whether there is a monotonic association, an association that does not increase or decrease but remains static across a dimension.

Recall the youth disconnection rates for Native Americans, some of the highest in the first table we examined.

Let’s conduct a Mann-Kendall test for trend.

We can accomplish this with the Kendall::MannKendall() function. The Kendall::MannKendall() accepts a vector of data for which a trend may be observed. Consulting the documentation for the Kendall::MannKendall() function available on CRAN, we can “test for a a monotonic trend in a time series”.

Score =  -7 , Var(Score) = 28.33333
denominator =  15
tau = -0.467, 2-sided pvalue =0.25966

There does not appear to be a change in the trend. However, it’s important to note that we only have 6 observations.

We can also explore the trend using simple linear regression.


Call:
lm(formula = Rate ~ Year, data = .)

Residuals:
      1       2       3       4       5       6 
-2.4332  2.2978  0.8288  0.4597  0.2907 -1.4438 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)
(Intercept) 359.1159   487.3956   0.737    0.502
Year         -0.1655     0.2421  -0.683    0.532

Residual standard error: 1.889 on 4 degrees of freedom
Multiple R-squared:  0.1045,    Adjusted R-squared:  -0.1193 
F-statistic: 0.467 on 1 and 4 DF,  p-value: 0.5319

For each one year change, the mean increase in disconnection rates is -0.1654795. This relationship is not statistically significant. Again, we are largely limited by the number of observations in this dataset.

We can visualize the relationship above.

As we can see, there is a large amount of uncertainty around the fitted line.

Let’s visualize the data!

Data Visualization


Let’s reproduce the example below.

We can create a version of the above example with ggplot from tidyverse.

There are color identifying websites only such as this.

Using one of these websites, we identify the hex triplet for the color used in the visualization included in the PDF: #008393.

We can build off of this idea, using a custom color palette to create a gradient based off the color used.

From the above plot, it becomes apparent that the Hmong subgroup produces a small proportion of the total number of asian disconnected youth. The Asian total youth disconnection rate is more alike the youth disconnection rates for all other subgroups than the Hmong youth disconnection rate.

We can confirm this by revisiting the table.

The Hmong group represents 6% of all Asian disconnected youth.

This shows the importance of adding small details such as the composite line to plots. It helps provide a simple yet nuanced picture of what is going on.

Lastly, we can add annotations to add provide even more depth to the visualization.

Summary


Suggested Homework


  1. Find another table in the document. Find differences between groups with the process described above.

Acknowledgements

We would like to acknowledge Tamar Mendelson for assisting in framing the major direction of the case study.

We would also like to acknowledge the Bloomberg American Health Initiative for funding this work.

LS0tCnRpdGxlOiAiT3BlbiBDYXNlIFN0dWRpZXMgOiBEaXNwYXJpdGllcyBpbiBZb3V0aCBEaXNjb25uZWN0aW9uIgpjc3M6IHN0eWxlLmNzcwpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIHNlbGZfY29udGFpbmVkOiB5ZXMKICAgIGNvZGVfZG93bmxvYWQ6IHllcwogICAgaGlnaGxpZ2h0OiB0YW5nbwogICAgbnVtYmVyX3NlY3Rpb25zOiBubwogICAgdGhlbWU6IGNvc21vCiAgICB0b2M6IHllcwogICAgdG9jX2Zsb2F0OiB5ZXMKICBwZGZfZG9jdW1lbnQ6CiAgICB0b2M6IHllcwogIHdvcmRfZG9jdW1lbnQ6CiAgICB0b2M6IHllcwoKLS0tCgo8c3R5bGU+CiNUT0MgewogIGJhY2tncm91bmQ6IHVybCgiaHR0cHM6Ly9vcGVuY2FzZXN0dWRpZXMuZ2l0aHViLmlvL2ltZy9sb2dvLmpwZyIpOwogIGJhY2tncm91bmQtc2l6ZTogY29udGFpbjsKICBwYWRkaW5nLXRvcDogMjQwcHggIWltcG9ydGFudDsKICBiYWNrZ3JvdW5kLXJlcGVhdDogbm8tcmVwZWF0Owp9Cjwvc3R5bGU+CgoKCgoKCgo8c3R5bGU+CmRpdi5yZWQgeyBiYWNrZ3JvdW5kLWNvbG9yOiNmZmNjY2I7IGJvcmRlci1yYWRpdXM6IDVweDsgcGFkZGluZzogMjBweDt9Cjwvc3R5bGU+CjxkaXYgY2xhc3MgPSAicmVkIj4KCioqTUlDSEFFTCBPTlRJVkVST1MqKgoKKlRoZXJlIGFyZSBzb21lIGV4aXN0aW5nIHR5cG9zIGluIHRoZSB0YWJsZXMgaW4gYWRkaXRpb24gdG8gdGhvc2UgcHJvZHVjZWQgZHVyaW5nIHRoZSB1c2Ugb2YgTWFnaWNrLiBJIG1hZGUgc29tZSBhc3N1bXB0aW9ucyBhbG9uZyB0aGUgd2F5LCBkb2N1bWVudGluZyB0aGVtLiBUaGVzZSBuZWVkIHRvIGJlIGNoZWNrZWQgZm9yIGFjY3VyYWN5LioKPC9kaXY+CgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGluY2x1ZGUgPSBUUlVFLCBjb21tZW50ID0gTkEsIGVjaG8gPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0UsIGNhY2hlID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICBmaWcuYWxpZ24gPSAiY2VudGVyIiwgb3V0LndpZHRoID0gJzkwJScpCmxpYnJhcnkoaGVyZSkKbGlicmFyeShrbml0cikKYGBgCgoKIyMjIyB7Lm91dGxpbmUgfQpgYGB7ciwgZWNobyA9IEZBTFNFLCBvdXQud2lkdGggPSAiODAwIHB4IiwgZXZhbD1GQUxTRX0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwgIm1haW5wbG90LnBuZyIpKQpgYGAKCiMjIyMKCiMjIHsuZGlzY2xhaW1lcl9ibG9ja30KCioqRGlzY2xhaW1lcioqOiBUaGUgcHVycG9zZSBvZiB0aGUgW09wZW4gQ2FzZSBTdHVkaWVzXShodHRwczovL29wZW5jYXNlc3R1ZGllcy5naXRodWIuaW8pe3RhcmdldD0iX2JsYW5rIn0gcHJvamVjdCBpcyAqKnRvIGRlbW9uc3RyYXRlIHRoZSB1c2Ugb2YgdmFyaW91cyBkYXRhIHNjaWVuY2UgbWV0aG9kcywgdG9vbHMsIGFuZCBzb2Z0d2FyZSBpbiB0aGUgY29udGV4dCBvZiBtZXNzeSwgcmVhbC13b3JsZCBkYXRhKiouIEEgZ2l2ZW4gY2FzZSBzdHVkeSBkb2VzIG5vdCBjb3ZlciBhbGwgYXNwZWN0cyBvZiB0aGUgcmVzZWFyY2ggcHJvY2VzcywgaXMgbm90IGNsYWltaW5nIHRvIGJlIHRoZSBtb3N0IGFwcHJvcHJpYXRlIHdheSB0byBhbmFseXplIGEgZ2l2ZW4gZGF0YSBzZXQsIGFuZCBzaG91bGQgbm90IGJlIHVzZWQgaW4gdGhlIGNvbnRleHQgb2YgbWFraW5nIHBvbGljeSBkZWNpc2lvbnMgd2l0aG91dCBleHRlcm5hbCBjb25zdWx0YXRpb24gZnJvbSBzY2llbnRpZmljIGV4cGVydHMuIAoKCiMjIHsubGljZW5zZV9ibG9ja30KClRoaXMgd29yayBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQ3JlYXRpdmUgQ29tbW9ucyBBdHRyaWJ1dGlvbi1Ob25Db21tZXJjaWFsIDMuMCBbKENDIEJZLU5DIDMuMCldKGh0dHBzOi8vY3JlYXRpdmVjb21tb25zLm9yZy9saWNlbnNlcy9ieS1uYy8zLjAvdXMvKXt0YXJnZXQ9Il9ibGFuayJ9ICBVbml0ZWQgU3RhdGVzIExpY2Vuc2UuCgoKIyMgey5yZWZlcmVuY2VfYmxvY2t9CgpUbyBjaXRlIHRoaXMgY2FzZSBzdHVkeSBwbGVhc2UgdXNlOgoKV3JpZ2h0LCBDYXJyaWUsIGFuZCBPbnRpdmVyb3MsIE1pY2hhZWwgYW5kIEphZ2VyLCBMZWFoIGFuZCBUYXViLCBNYXJnYXJldCBhbmQgSGlja3MsIFN0ZXBoYW5pZS4gKDIwMjApLiBodHRwczovL2dpdGh1Yi5jb20vb3BlbmNhc2VzdHVkaWVzL29jcy15b3V0aC1kaXNjb25uZWN0aW9uLWNhc2Utc3R1ZHkuIERpc3Bhcml0aWVzIGluIFlvdXRoIERpc2Nvbm5lY3Rpb24gKFZlcnNpb24gdjEuMC4wKS4KCiMjICoqTW90aXZhdGlvbioqCioqKiAKCkFjY29yZGluZyB0byB0aGlzIFtyZXBvcnRdKGh0dHBzOi8vc3NyYy1zdGF0aWMuczMuYW1hem9uYXdzLmNvbS9tb2EvTWFraW5nJTIwdGhlJTIwQ29ubmVjdGlvbi5wZGYpIHlvdXRoIGRpc2Nvbm5lY3Rpb24gYWx0aG91Z2ggZ2VuZXJhbGx5IHNob3dpbmcgZGVjcmVhc2luZyB0cmVuZHMgZm9yIHRoZSBwYXN0IDcgeWVhcnMsIHNob3dzICoqcmFjaWFsIGFuZCBldGhuaWMgZGlzcGFyaXRpZXMqKiwgd2hlcmUgc29tZSBncm91cHMgYXJlIHNob3dpbmcgaW5jcmVhc2VkIHJhdGVzIG9mIGRpc2Nvbm5lY3Rpb24uCgpTbyB3aGF0IGRvZXMgdGhlIHRlcm0gKioieW91dGggZGlzY29ubmVjdGlvbiIqKiBtZWFuPwoKQWNjb3JkaW5nIHRvIFtNZWFzdXJlIG9mIEFtZXJpY2FdKGh0dHBzOi8vd3d3LnNzcmMub3JnL3Byb2dyYW1zL3ZpZXcvbW9hLyl7dGFyZ2V0PSJfYmxhbmsifSAoYSBub25wYXJ0aXNhbiBwcm9qZWN0IG9mIHRoZSBub25wcm9maXQgW1NvY2lhbCBTY2llbmNlIFJlc2VhcmNoIENvdW5jaWxdKGh0dHBzOi8vd3d3LnNzcmMub3JnLyl7dGFyZ2V0PSJfYmxhbmsifSB0aGF0IGlzIGZvY3VzZWQgb24gb3Bwb3J0dW5pdHkgaW4gdGhlIFVuaXRlZCBTdGF0ZXMpIGRpc2Nvbm5lY3RlZCB5b3V0aCBhcmU6Cgo+ICJ5b3VuZyBwZW9wbGUgYmV0d2VlbiB0aGUgYWdlcyBvZiAqKjE2IGFuZCAyNCoqIHdobyBhcmUgKipuZWl0aGVyIHdvcmtpbmcgbm9yIGluIHNjaG9vbCoqIgoKVGhleSBzdGF0ZSB0aGF0IHN1Y2ggZGlzY29ubmVjdGlvbiBoaW5kZXJzIHRoZXNlIGluZGl2aWR1YWxzIHRvIGFxdWlyZSBza2lsbHMgYW5kIGNyZWF0ZSByZWxhdGlvbnNoaXBzIG5lY2Vzc2FyeSB0byBoYXZlIGEgc3VjZXNzZnVsIGFkdWx0aG9vZC4gCgpUaGV5IHN0YXRlIHRoYXQ6Cgo+ICJwZW9wbGUgd2hvIGV4cGVyaWVuY2UgYSBwZXJpb2Qgb2YgZGlzY29ubmVjdGlvbiBhcyB5b3VuZyBhZHVsdHMgZ28gb24gdG8gKiplYXJuIGxlc3MqKiBhbmQgYXJlICoqbGVzcyBsaWtlbHkqKiB0byBiZSAqKmVtcGxveWVkLCBvd24gYSBob21lLCBvciByZXBvcnQgZ29vZCBoZWFsdGgqKiBieSB0aGUgdGltZSB0aGV5IHJlYWNoIHRoZWlyIHRoaXJ0aWVzIgoKRGlzY29ubmVjdGVkIHlvdXRoIGFyZSBhbHNvIHJlZmVycmVkIHRvIGFzICoqb3Bwb3J0dW5pdHkgeW91dGgqKiwgd2hpY2ggaGFzIHRoZSBhZGRlZCBwb3NpdGl2ZSBjb25ub3RhdGlvbiB0aGF0IHByb21vdGluZyBzdWNoIGluZGl2aWR1YWxzIGNhbiBiZSBiZW5lZmljaWFsIG5vdCBvbmx5IGZvciB0aGVzZSBpbmRpdmlkdWFscyBidXQgYWxzbyBmb3IgdGhlaXIgY29tbXVudGllcyBhbmQgZm9yIHNvY2lldHkuIAoKV2Ugd2lsbCBleHBhbmQgYmV5b25kIHRoZSBbTWVhc3VyZSBvZiBBbWVyaWNhIGFubnVhbCByZXBvcnRdKGh0dHBzOi8vc3NyYy1zdGF0aWMuczMuYW1hem9uYXdzLmNvbS9tb2EvTWFraW5nJTIwdGhlJTIwQ29ubmVjdGlvbi5wZGYpe3RhcmdldD0iX2JsYW5rIn0gdG8gdGFrZSBhIGRlZXBlciBsb29rIGF0IGRpZmZlcmVuY2VzIG9mIHNwZWNpZmljIGdyb3VwcyBvZiB5b3V0aHMuIElkZW50aWZ5aW5nIHlvdXRocyBwYXJ0aWN1bGFybHkgYXQgcmlzayBvciBkaXNjb25uZWN0ZWQsIGNhbiBoZWxwIGluZm9ybSB0aGUgZGVzaWduIG9mIHRhcmdldGVkIHByZXZlbnRpb24gYW5kIHJlbmdhZ2VtZW50IHN0cmF0ZWdpZXMuCgpUaGlzIGNhc2Ugc3R1ZHkgaXMgbW90aXZhdGVkIGJ5IHRoaXMgW2FydGljbGVdKGh0dHBzOi8vd3d3Lm5jYmkubmxtLm5paC5nb3YvcG1jL2FydGljbGVzL1BNQzYyNDM0NDYvKXt0YXJnZXQ9Il9ibGFuayJ9OiAKCiMjIyMgey5yZWZlcmVuY2VfYmxvY2t9CgpNZW5kZWxzb24sIFQuLCBNbWFyaSwgSy4sIEJsdW0sIFIuIFcuLCBDYXRhbGFubywgUi4gRi4gJiBCcmluZGlzLCBDLiBELiBPcHBvcnR1bml0eSBZb3V0aDogSW5zaWdodHMgYW5kIE9wcG9ydHVuaXRpZXMgZm9yIGEgUHVibGljIEhlYWx0aCBBcHByb2FjaCB0byBSZWVuZ2FnZSBEaXNjb25uZWN0ZWQgVGVlbmFnZXJzIGFuZCBZb3VuZyBBZHVsdHMuICpQdWJsaWMgSGVhbHRoIFJlcCogMTMzLCA1NFMtNjRTICgyMDE4KS4KCiMjIyMKIApUaGlzIFthcnRpY2xlXShodHRwczovL3d3dy5uY2JpLm5sbS5uaWguZ292L3BtYy9hcnRpY2xlcy9QTUM2MjQzNDQ2Lyl7dGFyZ2V0PSJfYmxhbmsifSBkZXNjcmliZXMgc3RyYXRlZ2llcyBmb3IgcHJldmVudGlvbiBvZiBkaXNjb25uZWN0aW9uIGFuZCByZWVuZ2FnZW1lbnQgb2YgZGlzY2Nvbm5lY3RlZCB5b3V0aCBhbmQgaG93IHN1Y2ggaW50ZXJ2ZW50aW9ucyBjb3VsZCBncmVhdGx5IHBvc2l0aXZlbHkgaW1wYWN0IG9wcG9ydHVuaXR5IHlvdXRoIGZvciB0aGUgZW50aXJlIHRyYWplY3Rvcnkgb2YgdGhlaXIgbGl2ZXMgYW5kIGZvciBmdXR1cmUgZ2VuZXJhdGlvbnMuIEl0IGFsc28gcG9pbnRzIG91dCB0aGF0IGluZGVlZCB0aGVpciBhcmUgZGlzcGFyaXRpZXMgYW1vbmcgZGlmZmVyZW50IHJhY2lhbC9ldGhuaWMgZ3JvdXBzLgoKCiMjICoqTWFpbiBRdWVzdGlvbnMqKgoqKiogCgojIyMjIHsubWFpbl9xdWVzdGlvbl9ibG9ja30KPGI+PHU+IE91ciBtYWluIHF1ZXN0aW9uczogPC91PjwvYj4KCjEpIEhvdyBoYXZlIHlvdXRoIGRpc2Nvbm5lY3Rpb24gcmF0ZXMgaW4gQW1lcmljYW4geW91dGggY2hhbmdlZCBzaW5jZSAyMDA4PyAgIAoyKSBJbiBwYXJ0aWN1bGFyLCBob3cgaGFzIHRoaXMgY2hhbmdlZCBmb3IgZGlmZmVyZW50IGdlbmRlciBhbmQgZXRobmljIGdyb3Vwcz8gQXJlIGFueSBncm91cHMgcGFydGljdWxhcmx5IGRpc2Nvbm5lY3RlZD8gCgojIyMjCgojIyAqKkxlYXJuaW5nIE9iamVjdGl2ZXMqKiAKKioqIAoKSW4gdGhpcyBjYXNlIHN0dWR5LCB3ZSB3aWxsIGRlbW9uc3RyYXRlIGhvdyB0byBpbXBvcnQgYW5kIHdyYW5nbGUgZGF0YSBhdmFpbGFibGUgaW4gdGhlIDx1PioqUCoqPC91Pm9ydGFibGUgPHU+KipEKio8L3U+b2N1bWVudCA8dT4qKkYqKjwvdT5vcm1hdCAoKipQREYqKikuIFdlIHdpbGwgZXNwZWNpYWxseSBmb2N1cyBvbiB1c2luZyBwYWNrYWdlcyBhbmQgZnVuY3Rpb25zIGZyb20gdGhlIFtgVGlkeXZlcnNlYF0oaHR0cHM6Ly93d3cudGlkeXZlcnNlLm9yZy8pe3RhcmdldD0iX2JsYW5rIn0sIHN1Y2ggYXMgYGRwbHlyYCwgYGdncGxvdDJgLiBUaGUgdGlkeXZlcnNlIGlzIGEgbGlicmFyeSBvZiBwYWNrYWdlcyBjcmVhdGVkIGJ5IFJTdHVkaW8uIFdoaWxlIHNvbWUgc3R1ZGVudHMgbWF5IGJlIGZhbWlsaWFyIHdpdGggcHJldmlvdXMgUiBwcm9ncmFtbWluZyBwYWNrYWdlcywgdGhlc2UgcGFja2FnZXMgbWFrZSBkYXRhIHNjaWVuY2UgaW4gUiBtb3JlIGxlZ2libGUgYW5kIGludHVpdGl2ZS4KClRoZSBza2lsbHMsIG1ldGhvZHMsIGFuZCBjb25jZXB0cyB0aGF0IHN0dWRlbnRzIHdpbGwgYmUgZmFtaWxpYXIgd2l0aCBieSB0aGUgZW5kIG9mIHRoaXMgY2FzZSBzdHVkeSBhcmU6CgpEYXRhIHNjaWVuY2Ugc2tpbGxzOiAgCgoxLiBJbXBvcnRpbmcgZGF0YSBmcm9tIFBERiBmaWxlcyB1c2luZyB0aGUgYG1hZ2lja2AgcGFja2FnZSAgCjIuIEFwcGx5IGFjdGlvbiB2ZXJicyBpbiBgZHBseXJgIGZvciBkYXRhIHdyYW5nbGluZyAgCjMuIEhvdyB0byBwaXZvdCBiZXR3ZWVuICJsb25nIiBhbmQgIndpZGUiIGRhdGFzZXRzIChgdGlkeXJgKSAgCjQuIEpvaW5pbmcgdG9nZXRoZXIgbXVsdGlwbGUgZGF0YXNldHMgdXNpbmcgYGRwbHlyYCAgCjUuIEhvdyB0byBjcmVhdGUgZGF0YSB2aXN1YWxpemF0aW9ucyB3aXRoIGBnZ3Bsb3QyYCB0aGF0IGFyZSBpbiBhIHNpbWlsYXIgc3R5bGUgdG8gYW4gZXhpc3RpbmcgaW1hZ2UgIAoKU3RhdGlzdGljYWwgY29uY2VwdHMgYW5kIG1ldGhvZHM6ICAKCjEuIEltcGxlbWVudGF0aW9uIG9mIHRoZSBNYW5uLUtlbmRhbGwgdHJlbmQgdGVzdCAgCjIuIEludGVycHJldGF0aW9uIG9mIHRoZSBNYW5uLUtlbmRhbGwgdHJlbmQgdGVzdCAgCgoKYGBge3IsIG91dC53aWR0aCA9ICIyMCUiLCBlY2hvID0gRkFMU0UsIGZpZy5hbGlnbiA9ImNlbnRlciJ9CmluY2x1ZGVfZ3JhcGhpY3MoImh0dHBzOi8vdGlkeXZlcnNlLnRpZHl2ZXJzZS5vcmcvbG9nby5wbmciKQpgYGAKCioqKiAKCldlIHdpbGwgYmVnaW4gYnkgbG9hZGluZyB0aGUgcGFja2FnZXMgdGhhdCB3ZSB3aWxsIG5lZWQ6CgpgYGB7cn0KbGlicmFyeShoZXJlKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShwZGZ0b29scykKbGlicmFyeShtYWdpY2spCmxpYnJhcnkoY293cGxvdCkKbGlicmFyeShLZW5kYWxsKQpgYGAKCgoKIFBhY2thZ2UgICB8IFVzZSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKLS0tLS0tLS0tLSB8LS0tLS0tLS0tLS0tLQpbKipoZXJlKipdKGh0dHBzOi8vZ2l0aHViLmNvbS9qZW5ueWJjL2hlcmVfaGVyZSl7dGFyZ2V0PSJfYmxhbmsifSAgICAgICB8IHRvIGVhc2lseSBsb2FkIGFuZCBzYXZlIGRhdGEKWyoqdGlkeXZlcnNlKipdKGh0dHBzOi8vcmVhZHIudGlkeXZlcnNlLm9yZy8pe3RhcmdldD0iX2JsYW5rIn0gICAgICB8IGZvciBkYXRhIHNjaWVuY2Ugb3BlcmF0aW9ucwpbKipwZGZ0b29scyoqXShodHRwczovL3JlYWRyLnRpZHl2ZXJzZS5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9ICAgICAgfCB0byBtYW5hZ2UgUERGIGRvY3VtZW50cwpbKiptYWdpY2sqKl0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL21hZ2ljay92aWduZXR0ZXMvaW50cm8uaHRtbCNLZXJuZWxfY29udm9sdXRpb24pe3RhcmdldD0iX2JsYW5rIn0gICAgICB8IGZvciBpbWFnZSBwcm9jZXNzaW5nIAoKVGhlIGZpcnN0IHRpbWUgd2UgdXNlIGEgZnVuY3Rpb24sIHdlIHdpbGwgdXNlIHRoZSBgOjpgIHRvIGluZGljYXRlIHdoaWNoIHBhY2thZ2Ugd2UgYXJlIHVzaW5nLiBVbmxlc3Mgd2UgaGF2ZSBvdmVybGFwcGluZyBmdW5jdGlvbiBuYW1lcywgdGhpcyBpcyBub3QgbmVjZXNzYXJ5LCBidXQgd2Ugd2lsbCBpbmNsdWRlIGl0IGhlcmUgdG8gYmUgaW5mb3JtYXRpdmUgYWJvdXQgd2hlcmUgdGhlIGZ1bmN0aW9ucyB3ZSB3aWxsIHVzZSBjb21lIGZyb20uCgojIyAqKkNvbnRleHQqKgoqKiogCgpTbyBob3cgZG9lcyB5b3V0aCBkaXNjb25uZWN0aW9uIGhhcHBlbiBhbmQgd2hhdCBpbXBhY3QgZG9lcyBpdCBoYXZlPwoKClRoZXJlIGFyZSBtYW55IGtub3duICoqcmlzayBmYWN0b3JzKiosIHdoaWNoIGhhdmUgYmVlbiBpZGVudGlmaWVkIGluIGEgdmFyaWV0eSBvZiBjb250ZXh0cyAoZnJvbSBmYW1pbHksIGZyaWVuZHMsIHNjaG9vbCwgY29tbXVuaXR5LCBzb2NpZXR5KSBpbmNsdWRpbmc6ICAKCiAtIHBvdmVydHkgKGRpc2Nvbm5lY3RlZCB5b3V0aCBhcmUgbmVhcmx5IHR3aWNlIGFzIGxpa2VseSB0byBsaXZlIGluIHBvdmVydHkgYW5kIHJlY2VpdmUgTWVkaWNhaWQpICAKIC0gcmFjaWFsL2V0aG5pYyBkaXNwYXJpdGllcyAoZmluZGluZ3Mgc3VnZ2VzdCB0aGF0IHRoZXNlIHBlcnNpc3QgZXZlbiB3aGVuIGNvbnRyb2xsaW5nIGZvciBpbmNvbWUpICAKIC0gcmVzaWRlbnRpYWwgZW52aXJvbm1lbnQgKGluIDIwMTYgd2hpbGUgMTEuNyUgd2FzIHRoZSBuYXRpb25hbCBhdmVyYWdlLCAyNCUgb2YgcGVvcGxlIGFnZSAxNi0yNCBpbiB0aGUgcnVyYWwgU291dGggd2VyZSBkaXNjb25uZWN0ZWQpICAKIC0gcG9vciBhY2FkZW1pYyBwZXJmb3JtYW5jZSAgCiAtIHBvb3IgbWVudGFsIGhlYWx0aCAgCiAtIHN1YnN0YW5jZSB1c2UgZGlzb3JkZXJzICAKIC0gcGFyZW50YWwgdW5lbXBsb3ltZW50ICAKIC0gdHJhdW1hIGV4cG9zdXJlICAKIC0gYXNzb2NpYXRpb24gd2l0aCBzb2NpYWxseSBkZXZpYW50IHBlZXJzIAogLSBzY2hvb2wgcG9saWNpZXMgc3VjaCBhcyAib25lIHN0cmlrZSBhbmQgeW91J3JlIG91dCIgLSB3aGljaCBpcyBhIHplcm8gdG9sZXJhbmNlIHNjaG9vbCBleHB1bHNpb24gcG9saWN5IGFuZCBzaG93biB0byBpbmNyZWFzZSBkcm9wb3V0cyBhbmQgaW5jYXJjZXJhdGlvbiByYXRlcwogCiBUaGVzZSByaXNrIGZhY3RvcnMgbWFrZSBpdCBtb3JlIGxpa2VseSBmb3IgeW91bmcgcGVvcGxlIHRvIG1pc3Mgb3V0IG9uIGVkdWNhdGlvbiwgdHJhaW5pbmcsIGFuZCBuZXR3b3JraW5nIHRoYXQgY2FuIGFjdCBhcyBhIGZvdW5kYXRpb24gZm9yIGEgc3VjZXNzZnVsIGNhcmVlci4KIApUaGVyZSBhcmUgYWxzbyBtYW55IGtub3duICoqbmVnYXRpdmUgY29uc2VxdWVuY2VzKiogYXNzb2NpYXRlZCB3aXRoIHlvdXRoIGRpc2Nvbm5lY3Rpb24gaW5jbHVkaW5nIGJ1dCBub3QgbGltaXRlZCB0bzoKCi0gY2hyb25pYyB1bmVtcGxveW1lbnQKLSBwb3ZlcnR5Ci0gcG9vciBtZW50aGFsIGhlYWx0aCBhbmQgcG9vciBnZW5lcmFsIGhlYWx0aCAoaW4gYSAyMDAyIHN0dWR5IC0geW91dGhzIGRpc2Nvb25lY3RlZCBmb3IgNiBvciBtb3JlIG1vbnRocyB3ZXJlIDMgdGltZXMgbW9yZSBsaWtlbHkgdG8gZGV2ZWxvcCBkZXByZXNzaW9uIG9yIG90aGVyIG1lbnRhbCBoZWFsdGggZGlzb3JkZXIpCi0gY3JpbWlhbCBiZWhhdmlvciAoaW4gYSAyMDAyIHN0dWR5IC0geW91dGhzIGRpc2Nvb25lY3RlZCBmb3IgNiBvciBtb3JlIG1vbnRocyB3ZXJlIDUgdGltZXMgbW9yZSBsaWtlbHkgdG8gaGF2ZSBhIGNyaW1pbmFsIHJlY29yZCkKLSBpbmNhcmNlcmF0aW9uCi0gZWFybHkgbW9ydGFsaXR5IAoKCmBgYHtyLCBvdXQud2lkdGg9ICI0MDBweCIsZWNobz1GQUxTRX0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwgImpvbi10eXNvbi1hanpOMkFZTmkxVS11bnNwbGFzaC5qcGciKSkKYGBgCjxzcGFuPlBob3RvIGJ5IDxhIGhyZWY9Imh0dHBzOi8vdW5zcGxhc2guY29tL0Bqb250eXNvbj91dG1fc291cmNlPXVuc3BsYXNoJmFtcDt1dG1fbWVkaXVtPXJlZmVycmFsJmFtcDt1dG1fY29udGVudD1jcmVkaXRDb3B5VGV4dCI+Sm9uIFR5c29uPC9hPiBvbiA8YSBocmVmPSJodHRwczovL3Vuc3BsYXNoLmNvbS9zL3Bob3Rvcy91bmVtcGxveW1lbnQ/dXRtX3NvdXJjZT11bnNwbGFzaCZhbXA7dXRtX21lZGl1bT1yZWZlcnJhbCZhbXA7dXRtX2NvbnRlbnQ9Y3JlZGl0Q29weVRleHQiPlVuc3BsYXNoPC9hPjwvc3Bhbj4KCkZ1cnRoZXJtb3JlLCBpbiAyMDEyIGl0IHdhcyBlc3RpbWF0ZWQgdGhhdCBlYWNoIGRpc2Nvbm5lY3RlZCB5b3V0aCBjb3N0cyB0YXhwYXllcnMgJDI1MDAwMCBkdXJpbmcgYSBsaWZlIHRpbWUgZHVlIHRvIGxvc3QgdGF4IHJldmVudWUgYW5kIGNvc3RzIGZvciBzb2NpYWwgc2VyY2ljZXMsIGhlYXRoIGNhcmUgYW5kIGNyaW1pbmFsIGp1c3RpY2UuCgpZb3V0aCBkaXNjb25uZWN0aW9uIGNhbiBiZSBkZXNjcmliZWQgYXMgYSBjb250aW51dW0sIGFzIHNvbWUgeW91dGhzIHdpbGwgYmUgZGlzY29ubmVjdGVkIGZvciBhIGJyaWVmIHRpbWUsIHdoaWxlIG90aGVycyBhcmUgY2hyb25pY2FsbHkgZGlzY29ubmVjdGVkLiBBZGRpdGlvbmFsbHksIHdoaWxlIGFuIGluZGl2aWR1YWwgd2hvIGlzIG91dCBvZiBzY2hvb2wgYW5kIHdvcmsgYW5kIGFsc28gaGFzIHBvb3Igc3VwcG9ydCBmcm9tIHRoZSByZWFsdGlvbnNoaXBzIG9mIG90aGVycyBtYXkgYmUgZnVydGhlciBkaXNjb25uZWN0ZWQgdGhhbiBhbiBpbmRpdmlkdWFsIHdobyBoYXMgc29jaWFsIHN1cHBvcnQuCgpIZXJlIGlzIGFuIGlsbHVzdHJhdGlvbiBvZiByaXNrIGZhY3RvcnMsIHByb3RlY3RpdmUgZmFjdG9ycyBhbmQgdGhlIGNvbnRpbnV1bSBvZiBkaXNjb25uZWN0aW9uOgoKYGBge3IsIGVjaG8gPSBGQUxTRSwgb3V0LndpZHRoID0gIjgwMCBweCJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoImltZyIsICJyaXNrX2ZhY3RvcnMucG5nIikpCmBgYAojIyMjIyBbW3NvdXJjZV1dKGh0dHBzOi8vd3d3Lm5jYmkubmxtLm5paC5nb3YvcG1jL2FydGljbGVzL1BNQzYyNDM0NDYvcGRmLzEwLjExNzdfMDAzMzM1NDkxODc5OTM0NC5wZGYpe3RhcmdldD0iX2JsYW5rIn0gCgoKIyMjIFN0cmF0ZWdpZXMgdG8gbWl0aWdhdGUgeW91dGggZGlzY29ubmVjdGlvbgoKTWFueSBwcm9ncmFtcyBoYXZlIGlkZW50aWZpZWQgdXNlZnVsIHN0cmF0ZWdpZXMgaW4gcmVuZ2FnaW5nIGRpc2Nvbm5lY3RlZCB5b3V0aCBvciBwcmV2ZW50aW5nIGRpc2Njb25lY3Rpb24gb2YgeW91dGguIAoKZ2VuZXJhbGx5IHNwZWFraW5nLCBtb3N0IHByb2dyYW1zIGZvY3VzIG9uIHJlZW5nYWdlbWVudCBzdHJhdGVnaWVzLCBob3dldmVyLCBwcmV2ZW50aW9uIHN0cmF0ZWdpZXMgYXJlIGxpa2VseSB0byBiZSBqdXN0IGFzIGltcG9ydGFudC4gCgpSZXNlcmFjaCBzdWdnZXN0cyB0aGF0IGFjdGl2ZSBpbnZvbHZlbWVudCB3aXRoIGF0IHJpc2sgeW91dGggZnJvbSBpbmZhbmN5IGFuZCBhY3Jvc3MgbXVsdGlwbGUgZGV2ZWxvcG1lbnRhbCBzdGFnZXMgdGhyb3VnaCB5b3VuZyBhZHVsdGhvb2Qgd2hvdWxkIGJlIHRoZSBtb3N0IGJlbmVmaWNpYWwuCgpJbiBmYWN0LCB0aGUgcXVhbGl0eSBvZiBwYXJlbnRhbCBjYXJlZ2l2aW5nIG9mIGluZmFudHMgYWdlIDYtMjQgbW9udGhzIGhhcyBhY3R1YWxseSBiZWVuIHNob3duIHRvIGJlIGEgcHJlZGljdG9yIG9mIGhpZ2ggc2Nob29sIGRyb3BvdXQgcmF0ZXMhIFRodXMgZWFybHkgaW50ZXJ2ZW50aW9ucyBtYXkgYmUgdmVyeSBpbXBvcnRhbnQgYW5kIGNvbnNpc3RlbnQgY29udGludWFsIGVuZ2FnZW1lbnQgbWF5IHByZXZlbnQgZnVydGhlciBkaXNjb25uZWN0aW9uIG9mIHlvdXRocy4KClByZXZlbnRpb24gc3RyYXRlZ2llcyBpbmNsdWRlOiAgCgotIFByZXNjaG9vbCAgCi0gW1RoZSBHb29kIEJlaGF2aW9yIEdhbWVdKGh0dHBzOi8vd3d3Lmdvb2RiZWhhdmlvcmdhbWUub3JnL2dvb2QtYmVoYXZpb3ItZ2FtZS13aGF0LWlzLWl0KXt0YXJnZXQ9Il9ibGFuayJ9ICAKLSBTdHJlbmd0aGVuaW5nIGZhbWlseSBhbmQgY29tbXVuaXR5IGNvbm5lY3Rpb25zICAKLSBQcm9tb3RpbmcgYWNhZGVtaWMgYW5kIGNhcmVlciBlbmdhZ2VtZW50ICAKLSBMaWZlIHNraWxscyB0cmFpbmluZyBmb3IgeW91dGhzIGFuZCBmYW1pbGllcyAgCi0gRWR1Y2F0aW9uIGFib3V0IHN1YnN0YW5jZSBhYnVzZSAgCi0gW0NvZ25pdGl2ZSBiZWhhdmlvcmFsIHRoZXJhcHldKGh0dHBzOi8vd3d3LmFwYS5vcmcvcHRzZC1ndWlkZWxpbmUvcGF0aWVudHMtYW5kLWZhbWlsaWVzL2NvZ25pdGl2ZS1iZWhhdmlvcmFsKXt0YXJnZXQ9Il9ibGFuayJ9ICAgIAoKClNlZSBbaGVyZV0oaHR0cHM6Ly95b3V0aC5nb3YvZXZpZGVuY2UtaW5ub3ZhdGlvbi9wcm9ncmFtLWRpcmVjdG9yeT9rZXl3b3Jkcz0mZmllbGRfcGRfZmFjdG9yc19yaXNrc190aWQ9NDEzJmZpZWxkX3BkX2ZhY3RvcnNfcHJvdGVjdGl2ZV90aWQ9QWxsKXt0YXJnZXQ9Il9ibGFuayJ9IGFuZCBbaGVyZV0oaHR0cHM6Ly9nb2MubWFyeWxhbmQuZ292L3dwLWNvbnRlbnQvdXBsb2Fkcy9zaXRlcy84LzIwMTUvMTAvUHJvZ3JhbS1Nb2RlbHMtZm9yLVNlcnZpbmctT3Bwb3J0dW5pdHktWW91dGgucGRmKXt0YXJnZXQ9Il9ibGFuayJ9IGZvciBsaXN0aW5ncyBvZiBwcm9ncmFtcyBkZWRpY2F0ZWQgdG8gcmVuZ2FnaW5nIGRpc2Nvbm5lY3RlZCB5b3V0aCBvciBwcmV2ZW50aW5nIGRpc2Nvbm5lY3Rpb24uCgpTZWUgW2hlcmVdKGh0dHBzOi8vd3d3LmNvbW11bml0aWVzdGhhdGNhcmUubmV0Lyl7dGFyZ2V0PSJfYmxhbmsifSBhbmQgCltoZXJlXShodHRwczovL2V4dGVuc2lvbi5wc3UuZWR1L3Byb21vdGluZy1zY2hvb2wtY29tbXVuaXR5LXVuaXZlcnNpdHktcGFydG5lcnNoaXBzLXRvLWVuaGFuY2UtcmVzaWxpZW5jZSl7dGFyZ2V0PSJfYmxhbmsifSBmb3IgcGFydGljdWxhciBleGFtcGxlcy4KCgpUaGUgc3RhdGlzdGljcyB1c2VkIGluIHRoaXMgc2VjdGlvbiBjYW1lIGZyb20gdGhpcyBbYXJ0aWNsZV0oaHR0cHM6Ly93d3cubmNiaS5ubG0ubmloLmdvdi9wbWMvYXJ0aWNsZXMvUE1DNjI0MzQ0Ni8pe3RhcmdldD0iX2JsYW5rIn0uCgojIyAqKkxpbWl0YXRpb25zKioKKioqIAoKVGhlcmUgYXJlIHNvbWUgaW1wb3J0YW50IGNvbnNpZGVyYXRpb25zIHJlZ2FyZGluZyB0aGlzIGRhdGEgYW5hbHlzaXMgdG8ga2VlcCBpbiBtaW5kOiAKCjEpIFRoaXMgZGF0YSB1c2VkIGluIHRoZSBbTWVhc3VyZSBvZiBBbWVyaWNhXShodHRwczovL3d3dy5zc3JjLm9yZy9wcm9ncmFtcy92aWV3L21vYS8pe3RhcmdldD0iX2JsYW5rIn0gIHByb2plY3QgcmVwb3J0cyBmcm9tIHRoZSBpcyBkZXJpdmVkIGZyb20gW0FtZXJpY2FuIENvbW11bml0eSBTdXJ2ZXkoQVNDKV0oaHR0cHM6Ly93d3cuY2Vuc3VzLmdvdi9wcm9ncmFtcy1zdXJ2ZXlzL2Fjcyl7dGFyZ2V0PSJfYmxhbmsifSB3aGljaCBleGNsdWRlcyBvciB1bmRlcnJlcHJlc2VudHMgY2VydGFpbiBvcHBvcnR1bml0eSB5b3V0aCBncm91cHMsIHN1Y2ggYXMgeW91dGhzIGluIHRoZSBqdXZlbmlsZSBqdXN0aWNlIHN5c3RlbSwgeW91dGhzIGluIHRoZSBmb3N0ZXIgY2FyZSBzeXN0ZW0sIGFuZCBob21lbGVzcyB5b3V0aHMgYXMgdGhlIHN1cnZleSBpcyBjb25kdWN0ZWQgb24gaG91c2Vob2xkcy4gRnVydGhlcm1vcmUsIHlvdXRocyB3aG8gbWF5IGJlIG1vcmUgZGlzY29ubmVjdGVkIGZvciBvdGhlciByZWFzb25zIGJlc2lkZXMgbm90IGJlaW5nIGluIHdvcmsgb3Igc2Nob29sLCBzdWNoIGFzIGRlYWxpbmcgd2l0aCB0aGUgYWRkZWQgY2hhbGxlbmdlIG9mIGJlaW5nIGEgdGVlbmFnZSBtb3RoZXIsIG9yIGJlaW5nIGFidXNlZCBpcyBub3QgYXZhaWxhYmxlIGluIHRoaXMgZGF0YXNldC4gVGh1cywgdGhpcyBkYXRhIGxpa2VseSB1bmRlcmVzdGltYXRlcyB5b3V0aCBkaXNjb25uZWN0aW9uIHJhdGVzLiAKCjIpIERhdGEgYWJvdXQgY2VydGFpbiBncm91cCBbaW50ZXJzZWN0aW9uc10oaHR0cHM6Ly93d3cudm94LmNvbS90aGUtaGlnaGxpZ2h0LzIwMTkvNS8yMC8xODU0Mjg0My9pbnRlcnNlY3Rpb25hbGl0eS1jb25zZXJ2YXRpc20tbGF3LXJhY2UtZ2VuZGVyLWRpc2NyaW1pbmF0aW9uKXt0YXJnZXQ9Il9ibGFuayJ9IChtZWFuaW5nIGZvciBleGFtcGxlIGluZGl2aWR1YWxzIG9mIGEgcGFydGljdWxhciBnZW5kZXIgYW5kIGV0aG5pY2l0eSkgb3IgcGFydGljdWxhciBncm91cHMgaW4gZ2VuZXJhbCBzdWNoIGFzIHNwZWNpZmljIGV0aG5pY2l0aWVzIG9yIGdlbmRlciBvciBzZXh1YWwgaWRlbnRpdHkgZ3JvdXBzIHN1Y2ggYXMgTEdCVCAobGVzYmlhbi9nYXkvYmlzZXh1YWwvdHJhbnNnZW5kZXIvcXVlZXIgYW5kIHF1ZXN0aW9uaW5nKSBvciBub25iaW5hcnkgZ2VuZGVyIHBvcHVsYXRpb25zIGlzIHVuZm9ydHVuYXRlbHkgbm90IGF2YWlsYWJsZSBpbiB0aGUgZGF0YSB1c2VkIGluIHRoaXMgYW5hbHlzaXMgYW5kIGluIG1vc3QgcmVzZWFyY2ggYWJvdXQgdGhpcyB0b3BpYy4gTHVja2lseSBob3dldmVyLCByZWNlbnQgeWVhcnMgb2YgdGhlIFtBQ1Mgc3VydmV5XShodHRwczovL3d3dy5jZW5zdXMuZ292L3Byb2dyYW1zLXN1cnZleXMvYWNzKXt0YXJnZXQ9Il9ibGFuayJ9IGhhcyBtb3JlIGRldGFpbGVkIGluZnJvbWF0aW9uIGFib3V0IGEgZ3JlYXRlciBudW1iZXIgb2YgcmFjaWFsIGFuZCBldGhuaWMgZ3JvdXBzIGFuZCByYWNpYWwvZXRobmljIGludGVyc2VjdGlvbnMuCgozKSBUaGUgc3RhdGlzdGljYWwgcHJvY2VkdXJlcyB3ZSBhcmUgdXNpbmcgbWF5IGJlIG92ZXJseSBzaW1wbGlzdGljLiAqSW4gYWxsIGRhdGEgYW5hbHlzaXMsIHdlIG5lZWQgdG8gYmUgd2FyeSBhYm91dCBkZXJpdmluZyBtZWFuaW5nIGZyb20gdGhlIHN0YXRpc3RpY2FsIHByb2NlZHVyZXMgd2UgdXNlKi4KCjQpIFVzaW5nIGltYWdlIHByb2Nlc3NpbmcgdG9vbHMgY2FuIGJlIHZlcnkgaGVscGZ1bC4gVGhlIG1hbm5lciBpbiB3aGljaCBkYXRhIGlzIG9idGFpbmVkIHdpdGggaW1hZ2UgcHJvY2Vzc2luZyB0b29scyBpcyB3aGF0IHdlIHdvdWxkIGRlc2NyaWJlIGFzIGEgKipibGFjayBib3ggcHJvY2VzcyoqLCA8dT4qYSBwcm9jZXNzIHdpdGgga25vd24gaW5wdXRzIGFuZCBvdXRwdXRzIGJ1dCB1bmtub3duIG1lY2hhbmljcyo8L3U+LiBCZWNhdXNlIHdlIGFyZSB1bmF3YXJlIG9mIGhvdyBvdXIgb3V0cHV0cyBhcmUgZ2VuZXJhdGVkIGZyb20gb3VyIGlucHV0cywgd2UgbmVlZCB0byBiZSB3YXJ5IG9mIHRoZSBvdXRwdXQuIFdpdGggdGhlIHNtYWxsIG91dHB1dCB3ZSBhcmUgY3JlYXRpbmcgaW4gdGhpcyBjYXNlIHN0dWR5LCBhIHZpc3VhbCBpbnNwZWN0aW9uIHNob3VsZCBzdWZmaWNlLiAKCgojIyAqKldoYXQgYXJlIHRoZSBkYXRhPyoqCioqKiAKCkluIHRoaXMgY2FzZSBzdHVkeSB3ZSB3aWxsIGJlIHVzaW5nIGRhdGEgcmVsYXRlZCB0byB5b3V0aCBkaXNjb25uZWN0aW9uIGZyb20gdGhlIHR3byBmb2xsb3dpbmcgcmVwb3J0cyBmcm9tIHRoZSBbTWVhc3VyZSBvZiBBbWVyaWNhXShodHRwczovL3d3dy5zc3JjLm9yZy9wcm9ncmFtcy92aWV3L21vYS8pe3RhcmdldD0iX2JsYW5rIn0gIHByb2plY3Q6Cgo+IE1lYXN1cmUgb2YgQW1lcmljYSBpcyBhIG5vbnBhcnRpc2FuIHByb2plY3Qgb2YgdGhlIG5vbnByb2ZpdCBbU29jaWFsIFNjaWVuY2UgUmVzZWFyY2ggQ291bmNpbF0oaHR0cHM6Ly93d3cuc3NyYy5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9ICBmb3VuZGVkIGluIDIwMDcgdG8gY3JlYXRlIGVhc3ktdG8tdXNlIHlldCBtZXRob2RvbG9naWNhbGx5IHNvdW5kIHRvb2xzIGZvciB1bmRlcnN0YW5kaW5nIHdlbGwtYmVpbmcgYW5kIG9wcG9ydHVuaXR5IGluIEFtZXJpY2EuIFRocm91Z2ggcmVwb3J0cywgaW50ZXJhY3RpdmUgYXBwcywgYW5kIGN1c3RvbS1idWlsdCBkYXNoYm9hcmRzLCBNZWFzdXJlIG9mIEFtZXJpY2Egd29ya3Mgd2l0aCBwYXJ0bmVycyB0byBicmVhdGhlIGxpZmUgaW50byBudW1iZXJzLCB1c2luZyBkYXRhIHRvIGlkZW50aWZ5IGFyZWFzIG9mIGhpZ2hlc3QgbmVlZCwgcGlucG9pbnQgbGV2ZXJzIGZvciBjaGFuZ2UsIGFuZCB0cmFjayBwcm9ncmVzcyBvdmVyIHRpbWUuCgoxLiBMZXdpcywgS3Jpc3Rlbi4gW01ha2luZyB0aGUgQ29ubmVjdGlvbjogVHJhbnNwb3J0YXRpb24gYW5kIFlvdXRoIERpc2Nvbm5lY3Rpb25dKGh0dHBzOi8vc3NyYy1zdGF0aWMuczMuYW1hem9uYXdzLmNvbS9tb2EvTWFraW5nJTIwdGhlJTIwQ29ubmVjdGlvbi5wZGYpe3RhcmdldD0iX2JsYW5rIn0gLiBOZXcgWW9yazogTWVhc3VyZSBvZiBBbWVyaWNhLCBTb2NpYWwgU2NpZW5jZSBSZXNlYXJjaCBDb3VuY2lsLCAyMDE5LiAgKERhdGEgdXAgdG8gMjAxNykKCmBgYHtyLCBvdXQud2lkdGg9IjQwMHB4IiwgZWNobyA9IEZBTFNFfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlOjpoZXJlKCJpbWciLCAiTWFraW5nX3RoZV9Db25uZWN0aW9uLnBuZyIpKQpgYGAKCjIuIDogTGV3aXMsIEtyaXN0ZW4uIFtBIERlY2FkZSBVbmRvbmU6IFlvdXRoIERpc2Nvbm5lY3Rpb24gaW4gdGhlIEFnZSBvZiBDb3JvbmF2aXJ1c10oaHR0cHM6Ly9zc3JjLXN0YXRpYy5zMy5hbWF6b25hd3MuY29tL21vYS9BRGVjYWRlVW5kb25lLnBkZil7dGFyZ2V0PSJfYmxhbmsifS4gTmV3IFlvcms6IE1lYXN1cmUgb2YgQW1lcmljYSwgU29jaWFsIFNjaWVuY2UgUmVzZWFyY2ggQ291bmNpbCwgMjAyMC4gKERhdGEgdXAgdG8gMjAxOCkKCmBgYHtyLCBvdXQud2lkdGg9IjQwMHB4IiwgZWNobyA9IEZBTFNFfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlOjpoZXJlKCJpbWciLCAiQV9EZWNhZGVfVW5kb25lLnBuZyIpKQpgYGAKClRoZSBkYXRhIHVzZWQgaW4gdGhlc2UgcmVwb3J0cyBjb21lcyBmcm9tIHRoZSBbQW1lcmljYW4gQ29tbXVuaXR5IFN1cnZleShBU0MpXShodHRwczovL3d3dy5jZW5zdXMuZ292L3Byb2dyYW1zLXN1cnZleXMvYWNzKXt0YXJnZXQ9Il9ibGFuayJ9LCB3aGljaCBpcyB0aGUgbGFyZ2VzdCBzdXJ2ZXkgY29uZHVjdGVkIGJ5IHRoZSBVbml0ZWQgU3RhdGVzIENlbnN1cyBCdXJlYXUuIFRoZSBzdXJ2ZXkgc3RhcnRlZCBpbiAyMDA1IGFuZCBjb2xsZWN0cyBkYXRhIGZvciAzLjUgbWlsbGlvbiBob3VzZWhvbGRzIGFubnVhbGx5LiBEYXRhIGlzIGNvbGxlY3RlZCBhYm91dCBhbmNlc3RyeSwgY2l0aXplaHNpcCwgaW5jb21lLCBlbXBsb3ltZW50LCBkaXNhYmlsaXR5IGFtb25nIG1hbnkgb3RoZXIgYXNwZWN0cy4gU2VlIFtoZXJlXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9BbWVyaWNhbl9Db21tdW5pdHlfU3VydmV5KXt0YXJnZXQ9Il9ibGFuayJ9IGZvciBtb3JlIGRldGFpbGVkIGluZm9ybWF0aW9uIGFib3V0IHRoZSBzdXJ2ZXkuCgpBY2NvcmRpbmcgdG8gV2lraXBlZGlhIChodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9BbWVyaWNhbl9Db21tdW5pdHlfU3VydmV5KXt0YXJnZXQ9Il9ibGFuayJ9OgoKPiBEYXRhIGlzIGNvbGxlY3RlZCBieSBpbnRlcm5ldCwgbWFpbCwgdGVsZXBob25lIGludGVydmlld3MgYW5kIGluLXBlcnNvbiBpbnRlcnZpZXdzLi4uQWJvdXQgOTUgcGVyY2VudCBvZiBob3VzZWhvbGRzIGFjcm9zcyBhbGwgcmVzcG9uc2UgbW9kZXMgdWx0aW1hdGVseSByZXNwb25kLi4uIEFDUyByZXNwb25zZXMgYXJlIGNvbmZpZGVudGlhbC4uLiBhbmQgImltbXVuZSBmcm9tIGxlZ2FsIHByb2Nlc3MiCgo+IEl0IGlzIGEgbWFuZGF0b3J5IHN1cnZleSwgaXQgaXMgZ292ZXJuZWQgYnkgZmVkZXJhbCBsYXdzIHRoYXQgY291bGQgaW1wb3NlIGEgZmluZSBvZiBhcyBtdWNoIGFzICQ1LDAwMCBmb3IgcmVmdXNpbmcgdG8gcGFydGljaXBhdGUuCgoKV2UgYXJlIHBhcnRpY3VhcmxseSBpbnRlcmVzZWQgaW4gdGhlIGZvbGxvd2luZyB0YWJsZXMgb24gdGhlIGxhc3QgcGFnZSBvZiB0aGUgW01lYXN1cmUgb2YgQW1lcmljYSAyMDE5IHJlcG9ydF0oaHR0cHM6Ly9zc3JjLXN0YXRpYy5zMy5hbWF6b25hd3MuY29tL21vYS9NYWtpbmclMjB0aGUlMjBDb25uZWN0aW9uLnBkZil7dGFyZ2V0PSJfYmxhbmsifToKCmBgYHtyLCBlY2hvID0gRkFMU0UsIGdlbmRlcl9yYWNlX2V0aF8yMDE5fQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlOjpoZXJlKCJpbWciLCAiZ2VuZGVyX3JhY2VfZXRobmljaXR5X292ZXJ2aWV3LnBuZyIpKQpgYGAKCldlIGFyZSBwYXJ0aWN1YXJsbHkgaW50ZXJlc2VkIGluIHRoZSB0YWJsZXMgb24gdGhlIGZvbGxvd2luZyBwYWdlcyBmcm9tIHRoZSBbTWVhc3VyZSBvZiBBbWVyaWNhIDIwMjAgcmVwb3J0XShodHRwczovL3NzcmMtc3RhdGljLnMzLmFtYXpvbmF3cy5jb20vbW9hL0FEZWNhZGVVbmRvbmUucGRmKXt0YXJnZXQ9Il9ibGFuayJ9OgoKCmBgYHtyLCBlY2hvID0gRkFMU0V9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoImltZyIsICJsYXRpbm9fMjAxOF9vdmVydmlldy5wbmciKSkKYGBgCgpgYGB7ciwgZWNobyA9IEZBTFNFfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlOjpoZXJlKCJpbWciLCAiYXNpYW5fMjAxOF9vdmVydmlldy5wbmciKSkKYGBgCgoKCiMjICoqRGF0YSBJbXBvcnQqKgoqKiogCgpPbmUgd2F5IHRvIGltcG9ydCBkYXRhIGZyb20gYSBwZGYgaXMgdG8gdXNlIHRoZSBgcGRmX3RleHQoKWAgZnVuY3Rpb24gb2YgdGhlIGBwZGZ0b29sc2AgcGFja2FnZS4gVGhlIGBoZXJlKClgIGZ1bmN0aW9uIG9mIHRoZSBgaGVyZWAgcGFja2FnZSBjYW4gYWxsb3cgdXMgdG8gc3BlY2lmeSB3aGVyZSB0aGUgZG9jdW1lbnQgdGhhdCB3ZSB3YW50IHRvIGltcG9ydCBpcyBsb2NhdGVkIGVhc2lseSwgc3RhcnRpbmcgZnJvbSB0aGUgZGlyZWN0b3J5IHdoZXJlIGEgYC5ScHJvamAgZmlsZSBpcyBsb2NhdGVkLiBJbiB0aGlzIGNhc2UsIHdlIHdpbGwgaW1wb3J0IHRoZSBgTWFraW5nX3RoZV9Db25uZWN0aW9uLnBkZmAgaW4gdGhlIGBkb2NzYCBkaXJlY3RvcnkuICpOb3RlIHRoaXMgaXMgdGhlIGNhc2UgaWYgeW91IHB1bGwgdGhlIHJlcG9zaXRvcnkgZnJvbSBnaXRodWIuKgoKYGBge3J9CnBkZl90b29sc19leGFtcGxlIDwtIHBkZnRvb2xzOjpwZGZfdGV4dChoZXJlOjpoZXJlKCJkb2NzIiwiTWFraW5nX3RoZV9Db25uZWN0aW9uLnBkZiIpKQpgYGAKCldlIGNhbiB0YWtlIGEgbG9vayBhdCB0aGUgb3V0cHV0IGZvciB0aGUgcGFnZSB3aXRoIG91ciB0YWJsZSBvZiBpbnRlcmVzdHMgYnkgc2ltcHkgdXNpbmcgYnJhY2tldHMgYFtdYCBhcm91bmQgdGhlIHBhZ2UgbnVtYmVyLiBUaGUgcGFnZSB3ZSBhcmUgaW50ZXJlc3RlZCBpbiAoYXRob3VnaCBjYWxsZWQgMzkgaW4gdGhlIHJlcG9ydCkgaXMgdGhlIDQ0dGggcGFnZSwgd2hpY2ggbG9va3MgbGlrZSB0aGlzOgoKYGBge3IsIGdlbmRlcl9yYWNlX2V0aF8yMDE5LCBlY2hvPUZBTFNFfQpgYGAKCiMjIyMgey5zY3JvbGxhYmxlIH0KYGBge3J9CiMgU2Nyb2xsIHRocm91Z2ggdGhlIG91dHB1dCEKcGRmX3Rvb2xzX2V4YW1wbGVbNDRdCmBgYAojIyMjCgpGcm9tIHRoZSBvdXRwdXQsIGl0J3MgY2xlYXIgdGhhdCBhIHJlbGF0aXZlbHkgbGFyZ2UgYW1vdW50IG9mIG1hbmlwdWxhdGlvbiB3aWxsIGJlIHJlcXVpcmVkIHRvIHdyYW5nbGUgdGhpcyBkYXRhLiBJZiB5b3UgYXJlIGludGVyZXN0ZWQgaW4gbGVhcm5pbmcgbW9yZSBhYm91dCB0aGlzIG1ldGhvZCwgcGxlYXNlIHNlZSB0aGlzIFtjYXNlIHN0dWR5XShodHRwczovL29wZW5jYXNlc3R1ZGllcy5naXRodWIuaW8vb2NzLWJwLXJ1cmFsLWFuZC11cmJhbi1vYmVzaXR5Lyl7dGFyZ2V0PSJfYmxhbmsifSBhbmQgdGhpcyBbY2FzZSBzdHVkeV0oaHR0cHM6Ly9vcGVuY2FzZXN0dWRpZXMuZ2l0aHViLmlvL29jcy1icC1ydXJhbC1hbmQtdXJiYW4tb2Jlc2l0eS8pe3RhcmdldD0iX2JsYW5rIn0uCgpXaGlsZSBub3QgaW1wb3NzaWJsZSwgdXNpbmcgdGhlIGBwZGZ0b29sc2AgcGFja2FnZSBpbiB0aGlzIHNjZW5hcmlvIHdpbGwgcmVxdWlyZSBzb21lIGFkdmFuY2VkIGRhdGEgd3JhbmdsaW5nLgoKV2hpbGUgb3VyIG91dHB1dCBtYXkgYmUgcmVwcm9kdWNpYmxlLCB0aGlzIHByb2Nlc3MgbWF5IGJlIHRvbyB0aW1lIGNvbnN1bWluZy4KCkZvcnR1bmF0ZWx5LCB0aGVyZSBpcyBhbm90aGVyIHdheSB3ZSBjYW4gcHJvY2VlZCB0byB3cmFuZ2xlIHRoZSBkYXRhLiAKCldlIHdpbGwgZGVtb25zdHJhdGUgaG93IHRvIHByb2R1Y2UgcmVwcm9kdWNpYmxlIHRhYmxlcyB3aXRoIGltYWdlIHByb2Nlc3Npbmcgc29mdHdhcmUgaW4gYFJgIHVzaW5nICBhIHBhY2thZ2UgY2FsbGVkIGBtYWdpY2tgIHdoaWNoIGFsbG93cyBmb3IgdGhlIGV4dHJhY3Rpb24gb2YgdGV4dCBmcm9tIGltYWdlcy4KCkZvciBkZW1vbnN0cmF0aXZlIHB1cnBvc2VzLCB3ZSB3aWxsIGltcG9ydCB0d28gc2V0cyBvZiBkYXRhLiBUaGUgZmlyc3Qgc2V0IG9mIGRhdGEgd2lsbCBiZSB1c2VkIHRvIGhpZ2hsaWdodCBjb21tb24gZXJyb3JzIHRoYXQgdGhlIGltYWdlIHByb2Nlc3Npbmcgc29mdHdhcmUgbWF5IHByb2R1Y2UuIFRoZSBzZWNvbmQgc2V0IG9mIGRhdGEgd2lsbCBiZSB1c2VkIHRvIGRlbW9uc3RyYXRlIGhvdyB0byBjaXJjdW12ZW50IHRoZXNlIGVycm9ycyBhbmQgcHJvZHVjZSByZXByb2R1Y2libGUgZGF0YXNldHMgZWZmaWNpZW50bHkuCgoKIyMjIEltcG9ydGluZyB3aXRoIGBtYWdpY2tgCgpXZSB3aWxsIG5vdyBpbXBvcnQgdGhlIGRhdGEgdXNpbmcgdGhlIGBtYWdpY2tgIHBhY2thZ2Ugd2hpY2ggYWxsb3dzIGZvciB0aGUgaW1wcm90YXRpb24gb2YgaW1hZ2VzLiAKCkZpcnN0IHdlIHdpbGwgdGFrZSBhIHNjcmVlbnNob3Qgb2YgdGhlIHRvcCBwYXJ0IG9mIHRoZSBnZW5kZXIsIHJhY2UsIGFuZCBldGhuaWNpdHkgdGFibGUgb24gdGhlIGxhc3QgcGFnZSBvZiB0aGUgWzIwMTkgTWVhc3VyZSBvZiBBbWVyaWNhIFJlcG9ydF0oaHR0cHM6Ly9zc3JjLXN0YXRpYy5zMy5hbWF6b25hd3MuY29tL21vYS9NYWtpbmclMjB0aGUlMjBDb25uZWN0aW9uLnBkZil7dGFyZ2V0PSJfYmxhbmsifS4KCldlIGNhbiBzaG93IHdoYXQgdGhpcyBmaWxlIGxvb2tzIGxpa2UgaW4gdGhpcyByZW5kZXJlZCBybWFya2Rvd24gd2Vic2l0ZSBieSB1c2luZyB0aGUgYGluY2x1ZGVfZ3JhcGhpY3MoKWAgZnVuY3Rpb24gb2YgdGhlIGBrbml0cmAgcGFja2FnZS4KCmBgYHtyfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlOjpoZXJlKCJpbWciLCAiZ2VuZGVyX3JhY2VfZXRobmljaXR5LnBuZyIpKQpgYGAKCk5vdywgd2Ugd2lsbCB1c2UgdGhlIGBpbWFnZV9yZWFkKClgIGZ1bmN0aW9uIG9mIHRoZSBgbWFnaWNrYCBwYWNrYWdlIHRvIGltcG9ydCB0aGlzIGltYWdlLgoKV2UgY2FuIHRoZW4gdXNlIHRlaCBgaW1hZ2VfaW5mbygpYCBmdW5jdGlvbiB0byBtYWtlIHN1cmUgdGhhdCB0aGUgaW1wb3J0IHdvcmtlZCBhbmQgdG8gZ2V0IGluZm9ybWF0aW9uIGFib3V0IHRoZSBzaXplLCBmb3JtYXQgYW5kIGNvbG9yIG9mIHRoZSBpbWFnZS4KCmBgYHtyLCBkcGkgPSAxMDAwfQppbWFnZV9leGFtcGxlIDwtIG1hZ2ljazo6aW1hZ2VfcmVhZChoZXJlOjpoZXJlKCJpbWciLCAiZ2VuZGVyX3JhY2VfZXRobmljaXR5LnBuZyIpKQoKbWFnaWNrOjppbWFnZV9pbmZvKGltYWdlX2V4YW1wbGUpCmBgYApOb3cgbGV0J3MgdGFrZSBhIGxvb2sgYXQgb3VyIGltYWdlIGluIFIhIE5vdyB0aGF0IHdlIGhhdmUgaW1wb3J0ZWQgaXQgdG8gc2VlIHRoaXMgaW1hZ2UsIHdlIHNpbXBseSBuZWVkIHRvIHR5cGUgdGhlIG5hbWUgb2YgdGhlIGltYWdlLgoKYGBge3J9CmltYWdlX2V4YW1wbGUKYGBgCgpOaWNlIQoKV2Ugd2lsbCBkZW1vbnN0cmF0ZSBpbiBhIGJpdCB0aGF0IHRoZSB0b3AgcGFydCBvZiB0aGUgdGFibGUgY2F1c2VzIGlzc3VlcyB3aGVuIGV4dHJhY3RpbmcgdGhlIHRleHQgZnJvbSB0aGlzIGltYWdlLiAgU28gbm93IHdlIHdpbGwgdGFrZSBhIHNjcmVlbiBzaG90IHdpdGhvdXQgdGhlIHRvcCBwYXJ0IG9mIHRoZSB0YWJsZSBhbmQgZG8gdGhlIHNhbWUgcHJvY2Vzcy4KCmBgYHtyLCBkcGkgPSAxMDAwfQpjcm9wcGVkX3RhYmxlX2dlbl9yYWNlX2V0aF8yMDE4IDwtIGltYWdlX3JlYWQoaGVyZSgiaW1nIiwgImdlbmRlcl9yYWNlX2V0aG5pY2l0eTIucG5nIikpCmNyb3BwZWRfdGFibGVfZ2VuX3JhY2VfZXRoXzIwMTgKYGBgCkxldCdzIGltcG9ydCBvbmUgbW9yZSBpbWFnZSBqdXN0IGZvciBmdW4uIEhlcmUgd2Ugd2lsbCBpbXBvcnQgYW4gaW1hZ2UgZGlyZWN0bHkgZnJvbSBhIFVSTC4KCmBgYHtyLCBvdXQud2lkdGg9IjIwJSJ9CmdncGxvdDJfbG9nbyA8LSBpbWFnZV9yZWFkKCJodHRwczovL2QzM3d1YnJma2kwbDY4LmNsb3VkZnJvbnQubmV0LzJjNjIzOWQzMTFiZTZkMDM3YzI1MWM3MWMzOTAyNzkyZjhjNGRkZDIvMTJmNjcvY3NzL2ltYWdlcy9oZXgvZ2dwbG90Mi5wbmciKQpnZ3Bsb3QyX2xvZ28KYGBgCgpOb3cgd2Ugd2lsbCB1c2UgdGhlIGBpbWFnZV9vY3IoKWAgZnVuY3Rpb24gb2YgdGhlIGBtYWdpY2tgIHBhY2thZ2UgdG8gZXh0cmFjdCB0aGUgdGV4dCBmcm9tIHRoZSBPQ1MgbG9nbyBpbWFnZS4gVGhpcyBmdW5jdGlvbiB1c2VzIHRoZSBgdGVzc2VyYWN0YCBwYWNrYWdlIHdoaWNoIGhhcyB0b29scyBmb3IgW29wdGljYWwgY2hhcmFjdGVyIHJlY29nbml0aW9uIChPQ1IpXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9PcHRpY2FsX2NoYXJhY3Rlcl9yZWNvZ25pdGlvbil7dGFyZ2V0PSJfYmxhbmsifSwgaGVuY2UgdGhlIGBvY3JgIGluIHRoZSBmdW5jdGlvbiBuYW1lLiBUaGlzIGFsbG93cyB0aGUgZnVuY3Rpb24gdG8gaWRlbnRpZnkgdGV4dCBpbiBpbWFnZXMuIFRoZXNlIE9DUiB0b29scyBoYXZlIG9mdGVuIGJlZW4gZGV2ZWxvcGVkIHVzaW5nIFttYWNoaW5lIGxlYXJuaW5nXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9NYWNoaW5lX2xlYXJuaW5nKXt0YXJnZXQ9Il9ibGFuayJ9IGluIHdoaWNoIGFuIGFsZ29yaXRobSB3YXMgdHJhaW5lZCBvbiBpbWFnZXMgd2l0aCBhbmQgd2l0aG91dCB0ZXh0IHRvICJsZWFybiIgdG8gcmVjb2duaXplIHRleHQuIFNlZSBbaGVyZV0oaHR0cHM6Ly90b3dhcmRzZGF0YXNjaWVuY2UuY29tL2EtZ2VudGxlLWludHJvZHVjdGlvbi10by1vY3ItZWUxNDY5YTIwMWFhKXt0YXJnZXQ9Il9ibGFuayJ9IHRvIGxlYXJuIG1vcmUgYWJvdXQgaG93IE9DUiB3b3Jrcy4KCmBgYHtyfQptYWdpY2s6OmltYWdlX29jcihnZ3Bsb3QyX2xvZ28pCmBgYAoKQXdlc29tZSEgV2Ugd2VyZSBhYmxlIHRvIGV4dHJhY3QgdGV4dCBmcm9tIHRoaXMgaGV4IHN0aWNrZXIhCgpPbmUgdGhpbmcgdG8ga2VlcCBpbiBtaW5kIGlzIHRoYXQgdGhpcyBkb2Vzbid0IGFsd2F5cyB3b3JrLiBVbnVzdWFsIGZvbnQsIGFuZ2xlcyB0ZXh0LCBvciBwYXJ0aWN1bGFyIGNvbG9ycyBjYW4gYmUgZGlmZmljdWx0IGZvciB0aGUgT0NSIHRvIHJlY29naW5pemUuCgpIZXJlIGlzIGFuIGV4YW1wbGUgdGhhdCBkb2VzIG5vdCB3b3JrIHdpdGggdGhlIGN1cnJlbnQgdmVyc2lvbiBvZiBgbWFnaWNrYDoKCmBgYHtyLCBvdXQud2lkdGg9IjIwJSJ9CnRpZHl2ZXJzZV9sb2dvIDwtIGltYWdlX3JlYWQoImh0dHBzOi8vdGlkeXZlcnNlLnRpZHl2ZXJzZS5vcmcvbG9nby5wbmciKQp0aWR5dmVyc2VfbG9nbwptYWdpY2s6OmltYWdlX29jcih0aWR5dmVyc2VfbG9nbykKYGBgCgpUaGlzIGlzIGxpa2VseSBkbyB0byB0aGUgYmFja2dyb3VuZCBvbiB0aGlzIHBhcnRpY3VsYXIgaGV4IHN0aWNrZXIuCgojIyAqKkRhdGEgRXhwbG9yYXRpb24gYW5kIFdyYW5nbGluZyoqCioqKiAKTm93IGxldCdzIHRyeSBleHRyYWN0aW5nIHRoZSB0ZXh0IGZyb20gb3VyIGltYWdlIGZpbGVzLgoKVGhlIGZpcnN0IGltYWdlIHdlIGltcG9ydGVkIGxvb2tzIGxpa2UgdGhpcy4gCgpgYGB7cn0KaW1hZ2VfZXhhbXBsZQpgYGAKCk5vdyB3ZSB3aWxsIGV4dHJhY3QgdGhlIHRleHQhIAoKYGBge3J9CmRmMSA8LSBtYWdpY2s6OmltYWdlX29jcihpbWFnZV9leGFtcGxlKQpkZjEKYGBgClRoaXMgbG9va3MgbGlrZSBpdCB3b3JrZWQgZmFpcmx5IHdlbGwhCgpZb3UgbWF5IG5vdGljZSB0aGF0IHRoZXJlIGFyZSBsb3RzIG9mIGBcbmAgdmFsdWVzIGluIHRoZSB0ZXh0IGZyb20gb3VyIGltYWdlLiBUaGVzZSBhcmUgWyoqbmV3bGluZSoqXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9OZXdsaW5lP29sZGZvcm1hdD10cnVlKSBjaGFyYWN0ZXJzLCB3aGljaCBkZW5vdGUgdGhlIGVuZCBvZiBhIGxpbmUgb2YgdGV4dCBhbmQgdGhlIHN0YXJ0IG9mIGEgbmV3IGxpbmUgb2YgdGV4dC4gIAoKV2UgY2FuIHVzZSB0aGUgYHN0cl9zcGxpdCgpYCBmdW5jdGlvbiBvZiB0aGUgYHN0cmluZ3JgIHBhY2thZ2UgdG8gc3BsaXQgYmFzZWQgb24gdGhlIGBcbmAgY2hhcmFjdGVycyBpbiB0aGUgb3V0cHV0LiBXZSB3aWxsIHRoZW4gdW5saXN0IHRoZSBvdXRwdXQgdXNpbmcgdGhlIGJhc2UgUiBgdW5saXN0KClgIGZ1bmN0aW9uLiBCeSBiYXNlLCB3ZSBtZWFuIHRoYXQgdGhlIGZ1bmN0aW9uIGl0IGlzIGxvYWRlZCBhdXRvbWF0aWNhbGx5IGluIGFuIFIgc2Vzc2lvbi4gRmluYWxseSB3ZSB3aWxsIHVzZSB0aGUgYGFzX3RpYmJsZSgpYCBmdW5jdGlvbiBvZiB0aGUgYHRpYmJsZWAgcGFja2FnZSB0byBjb252ZXJ0IHRoZSBkYXRhIGludG8gW3RpYmJsZV0oaHR0cHM6Ly90aWJibGUudGlkeXZlcnNlLm9yZy8pe3RhcmdldD0iX2JsYW5rIn0gZm9ybWF0LCB3aGljaCBpcyB0aGUgdGlkeXZlcnNlIHZlcnNpb24gb2YgYSBkYXRhIGZyYW1lLiBUaGlzIHdpbGwgYWxsb3cgdXMgdG8gc2VlIHRoZSB2YWx1ZXMgaW4gdGhlIHRhYmxlIG11Y2ggYmV0dGVyLgoKVG8gZG8gYWxsIG9mIHRoZXNlIHNlcXVlbnRpYWwgc3RlcHMgZWZmaWNpZW50bHkgd2Ugd2lsbCB1c2UgYSBtZXRob2QgY2FsbGVkIHBpcGluZy4KCioqKgo8ZGV0YWlscz4gPHN1bW1hcnk+Q2xpY2sgaGVyZSBpZiB5b3UgYXJlIHVuZmFtaWxpYXIgd2l0aCBwaXBpbmcgaW4gUiwgd2hpY2ggdXNlcyB0aGlzIGAlPiVgIG9wZXJhdG9yPC9zdW1tYXJ5PiAgCgpCeSBbcGlwaW5nXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvbWFncml0dHIvdmlnbmV0dGVzL21hZ3JpdHRyLmh0bWwpe3RhcmdldD0iX2JsYW5rIn0gd2UgbWVhbiB1c2luZyB0aGUgYCU+JWAgcGlwZSBvcGVyYXRvciB3aGljaCBpcyBhY2Nlc3NpYmxlIGFmdGVyIGxvYWRpbmcgdGhlIGB0aWR5dmVyc2VgIG9yIHNldmVyYWwgb2YgdGhlIHBhY2thZ2VzIHdpdGhpbiB0aGUgdGlkeXZlcnNlIGxpa2UgYGRwbHlyYCBiZWNhdXNlIHRoZXkgbG9hZCB0aGUgW2BtYWdyaXR0cmAgcGFja2FnZV0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL21hZ3JpdHRyL3ZpZ25ldHRlcy9tYWdyaXR0ci5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9LiAKVGhpcyBhbGxvd3MgdXMgdG8gcGVyZm9ybSBtdWx0aXBsZSBzZXF1ZW50aWFsIHN0ZXBzIG9uIG9uZSBkYXRhIGlucHV0LiAgIAo8L2RldGFpbHM+ICAKKioqCiMjIyMgey5zY3JvbGxhYmxlIH0KYGBge3J9CmRmMSAlPiUKICBzdHJpbmdyOjpzdHJfc3BsaXQocGF0dGVybiA9IlxuIikgJT4lCiAgdW5saXN0KCkgJT4lCiAgdGliYmxlOjphc190aWJibGUoKQoKYGBgCiMjIyMKCgpPSywgbm90IGJhZCwgdGhlIHRvcCBsb29rcyBhIGJpdCBzdHJhbmdlIGJ1dCB0aGUgcmVzdCBvZiB0aGUgdGFibGUgbG9va3MgZmFpcmx5IGdvb2QsIGJ1dCB0aGVyZSBhcmUgc29tZSByb3dzIHRoYXQgbG9vayBwYXJ0aWN1bGFybHkgc3RyYW5nZSBsaWtlIHRoZSByb3cgdGhhdCBzdGFydHMgd2l0aCBgTEFUSU5PYCwgb3IgeW91IG1heSBub3RpY2UgdGhhdCB0aGUgcm93IGZvciBOYXRpdmUgQW1lcmljYW4gZmVtYWxlcyBlbmRzIHdpdGggYC1CLjRgOgoKCmBgYHtyLCBlY2hvID0gRkFMU0V9CgpkZjIgPC0gZGYxJT4lCiAgc3RyaW5ncjo6c3RyX3NwbGl0KHBhdHRlcm4gPSJcbiIpICU+JQogIHVubGlzdCgpICU+JQogIHRpYmJsZTo6YXNfdGliYmxlKCkKCnRlbXAgPC1kZjIgJT4lCiAgcHVsbCh2YWx1ZSkgJT4lCiAgc3RyX3NwbGl0KCIgIikKdGVtcFsxM10KdGVtcFsyMV0KYGBgCgpEYXRhIHdyYW5nbGluZyBpcyBub3QgYW4gZXhhY3Qgc2NpZW5jZS4gVGhlIGFwcHJvYWNoZXMgd2UgY2FuIHRha2UgYXJlIGV4dHJlbWVseSBkZXBlbmRlbnQgb24gdGhlIGRhdGEuIFdlIGNhbiBleHBsb2l0IHBhdHRlcm5zIGluIHRoZSBkYXRhIHRvIHJlbmRlciB0aGUgb3V0cHV0IHdlIGRlc2lyZS4gCgpUaGUgZmlyc3QgZmV3IGxpbmVzIG9mIG91ciB0YWJsZSBoYXZlIHF1aXRlIGEgYml0IG9mIHNwZWNpYWwgZm9ybWF0dGluZywgdGhlcmUgYXJlIGRpZmZlcmVudCBmb250IGNvbG9ycyBhbmQgYmFja2dyb3VuZHMuQXMgd2Ugc2F3IHByZXZpb3VzbHksIHRoaXMgY2FuIHNvbWV0aW1lcyBjYXVzZSBpc3N1ZXMuIFNvIG5vdyB3ZSB3aWxsIHRyeSB1c2UgdGhlIGNyb3BwZWQgdmVyc2lvbiBvZiB0aGUgaW1hZ2UuCgoKYGBge3IsIGRwaSA9IDEwMDB9Cgpjcm9wcGVkX3RhYmxlX2dlbl9yYWNlX2V0aF8yMDE4CgpkZjEgPC0gaW1hZ2Vfb2NyKGNyb3BwZWRfdGFibGVfZ2VuX3JhY2VfZXRoXzIwMTgpCgpkZjEgPC0gZGYxICU+JQogIHN0cl9zcGxpdCgiXG4iKSAlPiUKICB1bmxpc3QoKSAlPiUKICBhc190aWJibGUoKQoKZGYxCmBgYAoKVGhpcyBsb29rcyBtdWNoIGJldHRlciEKCkl0J3MgaW1wb3J0YW50IHRvIGxvb2sgdmVyeSBjYXJlZnVsbHkgYXQgdGhlIHRleHQuIE5vdyBhbHRob3VnaCB3ZSBubyBsb25nZXIgaGF2ZSB0aGUgcHJldmlvdXMgaXNzdWVzLiBUaGVyZSBhcmUgc29tZSB2YWx1ZXMgbWlzc2luZyBhIGRlY2ltYWwgcGxhY2UuIEZvciBleGFtcGxlIHRoZSByb3cgdGhhdCBzdGFydHMgd2l0aCBgQVNJQU5gLCB0aGUgZmlyc3QgdmFsdWUgaXMgbWlzc2luZyBhIGRlY2ltYWwgcGxhY2UuCgpOb3cgd2Ugd2lsbCB0cnkgdXNpbmcgc2VwYXJ0YXRlIGltYWdlcyBvZiBqdXN0IHRoZSBuYW1lcyBhbmQgdGhlIGRhdGEuIFdlIG9ubHkgd2FudCBkYXRhIGFib3V0IHRoZSBwZXJjZW50IGVhY2ggeWVhciwgc28gd2UgY2FuIGV4Y2x1ZGUgdGhlIGxhc3QgZmV3IGNvbHVtbnMgaW4gdGhpcyBpbWFnZS4gVGhlIGxhcmdlciBhbiBpbWFnZSBpcyBhbmQgdGhlIGJldHRlciB0aGUgcmVzb2x1dGlvbiwgdGhlIG1vcmUgbGlrZWx5IHRoYXQgdGhlIHRleHQgd2lsbCBiZSBleHRyYWN0ZWQgY29ycmVjdGx5LgoKYGBge3J9CgpldGhuaWNfZ3JvdXBzIDwtaW1hZ2VfcmVhZChoZXJlOjpoZXJlKCJpbWciLCAiZmlyc3RfdGFibGVfZXRobmljX2dyb3Vwcy5wbmciKSkKeWVhcnMgPC1pbWFnZV9yZWFkKGhlcmU6OmhlcmUoImltZyIsICJmaXJzdF90YWJsZV95ZWFycy5wbmciKSkKCmV0aG5pY19ncm91cHMKeWVhcnMKCmBgYApOb3cgbGV0J3MgdHJ5IGV4dHJhY3RpbmcgdGhlIHRleHQgZnJvbSB0aGVzZSBpbWFnZXMgYW5kIHNlcGFyYXRpbmcgdGhlIHJvd3MgYnkgdGhlICBuZXdsaW5lIGNoYXJhY3RlciBgXG5gLgoKIyMjIyB7LnF1ZXN0aW9uX2Jsb2NrfQo8Yj48dT4gUXVlc3Rpb24gT3Bwb3J0dW5pdHkgPC91PjwvYj4KCkNhbiB5b3UgcmVjYWxsIHRoZSBjb21tYW5kcyB0byBkbyB0aGlzPwoKIyMjIwoKCjxkZXRhaWxzPiA8c3VtbWFyeT4gQ2xpY2sgaGVyZSB0byByZXZlYWwgdGhlIGNvZGUuIDwvc3VtbWFyeT4KCmBgYHtyfQpldGhuaWNfZ3JvdXBzIDwtIGltYWdlX29jcihldGhuaWNfZ3JvdXBzKQp5ZWFycyA8LSBpbWFnZV9vY3IoeWVhcnMpCgpldGhuaWNfZ3JvdXBzIDwtIGV0aG5pY19ncm91cHMgJT4lCiAgc3RyX3NwbGl0KCJcbiIpICU+JQogIHVubGlzdCgpICU+JQogIGFzX3RpYmJsZSgpCgp5ZWFycyA8LXllYXJzICU+JQogIHN0cl9zcGxpdCgiXG4iKSAlPiUKICB1bmxpc3QoKSAlPiUKICBhc190aWJibGUoKQoKYGBgCgo8L2RldGFpbHM+CgoKYGBge3J9CmV0aG5pY19ncm91cHMKCnllYXJzCgpgYGAKT0shIHRoaXMgbG9va3MgcHJldHR5IGdvb2QhIFRoZSBvbmx5IGlzc3VlIGlzIHdlIGhhdmUgc29tZSBleHRyYSByb3dzIGluIGJldHdlZW4gZWFjaCByb3cgaW4gdGhlIGBldGhuaWNfZ3JvdXBzYCBvYmplY3QuCgpXZSBjYW4gcmVtb3ZlIHRoZXNlIGV4dHJhIHJvd3MgdXNpbmcgdGhlIGBmaWx0ZXIoKWAgZnVuY3Rpb24gb2YgdGhlIGBkcGx5cmAgcGFja2FnZSB0byBleGNsdWRlIGFsbCByb3dzIHRoYXQgYXJlIGp1c3QgYW4gZW1wdHkgc3RyaW5nIGFuZCB0aHVzIGEgc2V0IG9mIHF1b3RlcyBgIiJgIHVzaW5nIHRoZSBub3QgZXF1YWxzIG9wZXJhdG9yIGAhPWAuCgpXZSBhcmUgYWxzbyBnb2luZyB0byB1c2UgYSBzcGVjaWFsIHBpcGUgb3BlcmF0b3IgZnJvbSB0aGUgW2BtYWdyaXR0cmAgcGFja2FnZV0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL21hZ3JpdHRyL3ZpZ25ldHRlcy9tYWdyaXR0ci5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9IGNhbGxlZCB0aGUgY29tcG91bmQgYXNzaWdubWVudCBwaXBlLW9wZXJhdG9yIG9yIHNvbWV0aW1lcyB0aGUgZG91YmxlIHBpcGUgb3BlcmF0b3IuIAoKVGhpcyBhbGxvd3MgdXMgdG8gdXNlIHRoZSBgZXRobmljX2dyb3Vwc2AgYXMgb3VyIGlucHV0IGFuZCByZWFzc2lnbiBpdCBhdCB0aGUgZW5kIGFmdGVyIGFsbCB0aGUgc3RlcHMgaGF2ZSBiZWVuIHBlcmZvcm1lZC4KCmBgYHtyfQpsaWJyYXJ5KG1hZ3JpdHRyKQoKZXRobmljX2dyb3VwcyAlPD4lCiAgZmlsdGVyKHZhbHVlICE9ICIiKQoKZXRobmljX2dyb3VwcwpgYGAKCgpMZXQncyBhbHNvIGdldCByaWQgb2YgdGhlIGFsbCBjYXBzIGZvciB0aGUgbWFqb3IgY2F0ZWdvcmllcy4gV2UgY2FuIGNvbnZlcnQgdGhlIHdvcmRzIHRvIG9ubHkgY2FwaXRhbGl6ZSB0aGUgZmlyc3QgbGV0dGVyIHVzaW5nIHRoZSBgc3RyX3RvX3RpdGxlKClgIGZ1bmN0aW9uIG9mIHRoZSBgc3RyaW5ncmAgcGFja2FnZS4KCmBgYHtyfQpldGhuaWNfZ3JvdXBzICU8PiUKICBtdXRhdGUodmFsdWUgPSBzdHJpbmdyOjpzdHJfdG9fdGl0bGUodmFsdWUpKQpldGhuaWNfZ3JvdXBzCmBgYApOaWNlISB0aGF0IGxvb2tzIGJldHRlci4KCkZvciB0aGUgeWVhciBkYXRhIHdlIHdvdWxkIGxpa2UgdG8gdHJ5IHNwbGl0dGluZyB0aGUgc3RyaW5ncyBmb3IgZWFjaCByb3cgaW50byBkaWZmZXJlbnQgY29sdW1ucyBiYXNlZCBvbiBhIHNwYWNlLiBDdXJyZW50bHkgYWxsIHRoZSBkYXRhIGlzIGxpc3RlZCBpbiBvbmUgY29sdW1uIGNhbGxlZCBgdmFsdWVgLgoKV2UgY2FuIHVzZSB0aGUgYHNlcGFyYXRlYCBmdW5jdGlvbiBvZiB0aGUgYHRpZHlyYCBwYWNha2dlIHRvIGRvIHRoaXMuIFRoaXMgd2lsbCBhbGxvdyB1cyB0byBub3Qgb25seSBzcGxpdCB0aGUgcm93cyBieSBzcGFjZXMsIGJ1dCBhbHNvIHRvIGNyZWF0ZSBjb2x1bW4gbmFtZXMuCgpUaGVyZSBhcmUgdGhyZWUgaW1wb3J0YW50IGFyZ3VtZW50cyBmb3IgdGhlIGBzZXBlcmF0ZSgpYCBmdW5jdGlvbjogIAotIGBjb2xgIC0gdGhpcyBzcGVjaWZpZXMgd2hhdCBjb2x1bW4geW91IGFyZSBzZXBhcmF0aW5nICAgCi0gYGludG9gIC0gdGhpcyBzcGVjaWZpZXMgdGhlIG5hbWVzIG9mIHRoZSBuZXcgY29sdW1ucyB5b3UgYXJlIGNyZWF0aW5nICAKLSBgc2VwYCAtIHRoaXMgc3BlY2lmaWVzIHdoYXQgY2hhcmFjdGVyIHN0cmluZyB0byBsb29rIGZvciB0byBzZXBhcmF0ZSBieSAgCgojIyMjIHsuc2Nyb2xsYWJsZSB9CmBgYHtyfQoKeWVhcnMgJTw+JQp0aWR5cjo6c2VwYXJhdGUoY29sID0gdmFsdWUsIAogICAgICAgICAgICAgICBpbnRvID0gYygiMjAwOCIsICIyMDEwIiwKICAgICAgICAgICAgICAgICAgICAgICAiMjAxMiIsICIyMDE0IiwgCiAgICAgICAgICAgICAgICAgICAgICAgIjIwMTYiLCAiMjAxNyIpLCAKICAgICAgICAgICAgICAgIHNlcCA9ICIgIikKCiB5ZWFycwogCmBgYAojIyMjCgpMb29rcyBwcmV0dHkgZ29vZCEKCldlIGFwcGVhciB0byBoYXZlIGFuIGVtcHR5IHJvdyBhdCB0aGUgdmVyeSBlbmQuIFNpbmNlIGFsbCB0aGUgdmFsdWVzIGFyZSBgTkFgLCB3ZSBjYW4gdXNlIHRoZSBgZHJvcF9uYSgpYCBmdW5jdGlvbiAgb2YgdGhlIGB0aWR5cmAgcGFja2FnZSB0byByZW1vdmUgaXQuCgpgYGB7cn0KeWVhcnMgJTw+JQogIHRpZHlyOjpkcm9wX25hKCkKCnllYXJzCmBgYAoKCkdyZWF0ISBOb3cgd2Ugb25seSBoYXZlIDE4IHJvd3MuCgoKTm93IGxldCdzIG1ha2UgdGhlc2UgdmFsdWVzIG51bWVyaWMuIEN1cnJlbnRseSB3ZSBjYW4gdGVsbCB0aGF0IHRoZXkgYXJlIGNoYXJhY3RlciBzdHJpbmdzIGJhc2VkIG9uIHRoZSBgPGNoYXI+YCB2YWx1ZXMgbGlzdGVkIHVuZGVyIGVhY2ggY29sdW1uIG5hbWUuCgoKPGRldGFpbHM+IDxzdW1tYXJ5PiBDbGljayBoZXJlIGZvciBhbiBleHBsYW5hdGlvbiBvZiB3aGF0IGEgY2hhcmFjdGVyIHN0cmluZyBpcyA8L3N1bW1hcnk+CgpUaGVyZSBhcmUgc2V2ZXJhbCBjbGFzc2VzIG9mIGRhdGEgaW4gUiBwcm9ncmFtbWluZy4gCkNoYXJhY3RlciBpcyBvbmUgb2YgdGhlc2UgY2xhc3Nlcy4gCkEgY2hhcmFjdGVyIHN0cmluZyBpcyBhbiBpbmRpdmlkdWFsIGRhdGEgdmFsdWUgbWFkZSB1cCBvZiBjaGFyYWN0ZXJzLiAKVGhpcyBjYW4gYmUgYSBwYXJhZ3JhcGgsIGxpa2UgdGhlIGxlZ2VuZCBmb3IgdGhlIHRhYmxlLCBvciBpdCBjYW4gYmUgYSBzaW5nbGUgbGV0dGVyIG9yIG51bWJlciBsaWtlIHRoZSBsZXR0ZXIgYCJhImAgb3IgdGhlIG51bWJlciBgIjMiYC4gCklmIGRhdGEgYXJlIG9mIGNsYXNzIGNoYXJhY3RlciwgdGhhbiB0aGUgbnVtZXJpYyB2YWx1ZXMgd2lsbCBub3QgYmUgcHJvY2Vzc2VkIGxpa2UgYSBudW1lcmljIHZhbHVlIGluIGEgbWF0aGVtYXRpY2FsIHNlbnNlLiAKSWYgeW91IHdhbnQgeW91ciBudW1lcmljIHZhbHVlcyB0byBiZSBpbnRlcnByZXRlZCB0aGF0IHdheSwgdGhleSBuZWVkIHRvIGJlIGNvbnZlcnRlZCB0byBhIG51bWVyaWMgY2xhc3MuIApUaGUgb3B0aW9ucyB0eXBpY2FsbHkgdXNlZCBhcmUgaW50ZWdlciAod2hpY2ggaGFzIG5vIGRlY2ltYWwgcGxhY2UpIGFuZCBkb3VibGUgcHJlY2lzaW9uICh3aGljaCBoYXMgYSBkZWNpbWFsIHBsYWNlKS4gCgo8L2RldGFpbHM+CgoKVG8gY29udmVydCBvdXIgdmFsdWVzIHRvIGJlIG51bWVyaWMgd2UgY2FuIHVzZSB0aGUgYmFzZSBgYXMubnVtZXJpYygpYCBmdW5jdGlvbi4gVG8gYXBwbHkgdGhpcyB0byBhbGwgdGhlIHJvd3MgaW4gYHllYXJzYCB3ZSBjYW4gdXNlIHRoZSBgbWFwX2RmKClgIGZ1bmN0aW9uIG9mIHRoZSBgcHVycnJgIHBhY2thZ2UuIFRoZSBgbWFwKClgIHdvdWxkIGFsc28gd29yaywgaG93ZXZlciwgdGhlIHNwZWNpYWwgYG1hcF9kZigpYCBmdW5jdGlvbiBrZWVwcyB0aGUgb3V0cHV0IGluIHRoZSBzYW1lIHRpYmJsZSBmb3JtYXQuIEEgYC5gIGlzIG5lY2Vzc2FyeSB0byB0ZWxsIHRoZSBgbWFwX2RmKClgIGZ1bmN0aW9uIHRvIGFwcGx5IHRoZSBgYXNfbnVtZXJpYygpYCBmdW5jdGlvbiB0byB0aGUgdmFsdWVzIG9mIHRoZSBgeWVhcnNgIHRpYmJsZS4KCmBgYHtyfQogeWVhcnMgJTw+JQogICAgbWFwX2RmKC4sYXMubnVtZXJpYykKCnllYXJzCmBgYAoKCgpXZSBhcmUgbm93IHJlYWR5IHRvIHB1dCB0aGUgYGV0aG5pY19ncm91cHNgIGFuZCBgeWVhcnNgIG9iamVjdHMgdG9nZXRoZXIuCgpXZSBjYW4gZG8gc28gdXNpbmcgdGhlIGBjb2xfYmluZGAgZnVuY3Rpb24uCgpgYGB7cn0KZGlzY29ubmVjdGlvbiA8LSBiaW5kX2NvbHMoZXRobmljX2dyb3VwcywgeWVhcnMpCmBgYAoKVG8gcmVuYW1lIHRoZSBjb2x1bW4gbmFtZSBvZiB0aGUgYHZhbHVlYCB2YXJpYWJsZSBvZiB0aGUgYGRpc2Nvbm5lY3Rpb24gYCB0aWJibGUgd2Ugd2lsbCB1c2UgdGhlIGByZW5hbWUoKWAgZnVuY3Rpb24gb2YgdGhlIGBkcGx5cmAgcGFja2FnZS4KClRoZSBuZXcgbmFtZSBuZWVkcyB0byBiZSBsaXN0ZWQgZmlyc3QgYmVmb3JlIHRoZSBvbGQgbmFtZS4KCmBgYHtyfQpkaXNjb25uZWN0aW9uICU8PiUKICByZW5hbWUoIkdyb3VwIiA9IHZhbHVlKQoKYGBgCgpGcm9tIE1pY2hhZWw6CgpXZSBzcGxpdCB0aGUgZGF0YWZyYW1lIGluIHR3bzogYSBsYWJlbHMgc2VjdGlvbiBhbmQgYSAiZGF0YSIgc2VjdGlvbiBjb250YWluaW5nIHRoZSBpbmZvcm1hdGlvbiB3ZSBhcmUgaW50ZXJlc3RlZCBpbi4gCgpJbiB0aGUgZmlyc3QgaGFsZiwgd2UgcmVtb3ZlIGFsbCBkaWdpdHMgYW5kIHB1bmN0dWF0aW9uIHRvIGVuc3VyZSB0aGF0IHdlIGFyZSBsZWZ0IHdpdGggY2hhcmFjdGVyIGxhYmVscy4KCkluIHRoZSBzZWNvbmQtaGFsZiwgcmVtb3ZlIGNvbW1hcyBhbmQgcGVyaW9kcywgY29udmVydGluZyB0aGUgcmVzdWx0aW5nIHN0cmluZyBjaGFyYWN0ZXIgY2xhc3MgdG8gbnVtZXJpYyBhbmQgc2VsZWN0aXZlbHkgbXVsdGlwbHlpbmcgY29sdW1ucyB0byByZWludHJvZHVjZSB0aGUgZGVjaW1hbCBwb2ludCBjb3JyZWN0bHkuIAoKCgoKCgpgYGB7cn0KCmRmMSA8LSBkZjEgJT4lCiAgICBwdWxsKHZhbHVlKSAlPiUKICBzdHJfc3BsaXQoIiAiKQoKZGYxYSA8LSBkZjEgJT4lCiAgcHVycnI6Om1hcCh+YmFzZTo6cGFzdGUoLixjb2xsYXBzZSA9ICIiKSkgJT4lCiAgcHVycnI6Om1hcCh+YmFzZTo6Z3N1YigiW1s6ZGlnaXQ6XV0rfFtbOnB1bmN0Ol1dKyIsICIiLC4pKSAlPiUKICBiYXNlOjpkby5jYWxsKGJhc2U6OnJiaW5kLC4pICU+JQogIGJhc2U6OmRhdGEuZnJhbWUoKSAlPiUKICBkcGx5cjo6dGliYmxlKCkKCmRmMWIgPC0gbWFwKGRmMSwgdGFpbCwgOCkgJT4lCiAgbWFwKH5nc3ViKCJbLF0rfFsuXSsiLCAiIiwuKSkgJT4lCiAgZG8uY2FsbChyYmluZCwuKSAlPiUKICBkYXRhLmZyYW1lKCkgJT4lCiAgZHBseXI6Om11dGF0ZV9pZihiYXNlOjppcy5jaGFyYWN0ZXIsIGJhc2U6OmFzLm51bWVyaWMpICU+JQogIGRwbHlyOjptdXRhdGVfYXQodmFycygtWDcpLCB+IC4gKiAwLjEpICU+JQogIHRpYmJsZSgpIAoKYmFzZTo6cm0oZGYxKQpgYGAKCldlIGNvbWJpbmUgdGhlIHR3byBzZWN0aW9ucyBvZiBkYXRhIHRvIGNyZWF0ZSBvdXIgZGF0YWZyYW1lLCByZW1vdmluZyBhbmQgdGhlbiBhZGRpbmcgY29sdW1uIG5hbWVzLgoKYGBge3J9CmRmMSA8LSBkcGx5cjo6YmluZF9jb2xzKGRmMWEsCiAgICAgICAgICAgICAgICAgICAgICAgIGRmMWIpCgpiYXNlOjpuYW1lcyhkZjEpIDwtIGMoKQoKY29sdW1uX25hbWVzIDwtIGMoIkdyb3VwIiwKICAgICAgICAgICAgICAgICAgIlBlcmNfMjAwOCIsCiAgICAgICAgICAgICAgICAgICJQZXJjXzIwMTAiLAogICAgICAgICAgICAgICAgICAiUGVyY18yMDEyIiwKICAgICAgICAgICAgICAgICAgIlBlcmNfMjAxNCIsCiAgICAgICAgICAgICAgICAgICJQZXJjXzIwMTYiLAogICAgICAgICAgICAgICAgICAiUGVyY18yMDE3IiwKICAgICAgICAgICAgICAgICAgIk5fMjAxNyIsCiAgICAgICAgICAgICAgICAgICJEZWx0YV9wZXJjIikKCmJhc2U6OmNvbG5hbWVzKGRmMSkgPC0gY29sdW1uX25hbWVzCmBgYAoKV2UgcmVtb3ZlIGNvbHVtbnMgd2l0aCBpbmZvcm1hdGlvbiB3ZSBkb24ndCBuZWVkIGFuZCB1c2UgdGhlIGNvbW1tb24gcGF0dGVybiBpbiB0aGUgY29sdW1uIG5hbWVzIHRvIGNvbnZlcnQgdGhlIGRhdGEgaW50byBbbG9uZy9uYXJyb3cgZm9ybWF0XShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9XaWRlX2FuZF9uYXJyb3dfZGF0YT9vbGRmb3JtYXQ9dHJ1ZSkuCgoKCmBgYHtyfQpkZjEgPC0gZGYxICU+JQogIGRwbHlyOjpzZWxlY3QoLU5fMjAxNywKICAgICAgICAgICAgICAgIC1EZWx0YV9wZXJjKQoKZGYxIDwtIGRmMSAlPiUKICB0aWR5cjo6cGl2b3RfbG9uZ2VyKGNvbHM9Y29udGFpbnMoIlBlcmNfIiksCiAgICAgICAgICAgICAgICAgICAgICBuYW1lc190byA9ICJZZWFyIiwKICAgICAgICAgICAgICAgICAgICAgIHZhbHVlc190byA9ICJSYXRlIiwKICAgICAgICAgICAgICAgICAgICAgIG5hbWVzX3ByZWZpeCA9ICJQZXJjXyIpICU+JQogIGRwbHlyOjptdXRhdGUoWWVhciA9IGFzLm51bWVyaWMoWWVhcikpCmBgYAoKV2UgdXNlIHRoZSBgZHBseXI6OmNhc2Vfd2hlbigpYCBhbmQgYHN0cmluZ3I6OnN0cl9kZXRlY3QoKWAgZnVuY3Rpb24gdG8gZGV0ZWN0IHBhdHRlcm5zIGFuZCBjcmVhdGUgYW4gc2VwYXJhdGUgY29sdW1uIHdpdGggZ2VuZGVyIGFuZCByYWNlIGluZm9ybWF0aW9uLgoKVGhlIHR3byBjb2x1bW5zIGNyZWF0ZWQgY29udGFpbiBgVFJVRS9GQUxTRWAgc3RhdGVtZW50cy4gVGhlc2UgYXJlIHRoZW4gdXNlZCB0byBjcmVhdGUgYSB0aGlyZCBjb2x1bW4gdGhhdCB3aWxsIGFsbG93IHVzIHRvIHNlcGFyYXRlIHRoZSBkYXRhIGJ5IGl0cyBzdW1tYXJ5IGxldmVsLiAKCmBgYHtyfQpkZjEKYGBgCgpgYGB7cn0KCmRpc2Nvbm5lY3Rpb24gJTw+JSAKICBtdXRhdGUoUmFjZSA9IHJlY29kZShHcm91cCwgIlVuaXRlZCBTdGF0ZXMiID0gIkFsbF9yYWNlcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRmVtYWxlIiA9ICJBbGxfcmFjZXMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTWFsZSIgPSAiQWxsX3JhY2VzIikpICU+JQogIG11dGF0ZShSYWNlID0gc3RyX3JlbW92ZShSYWNlLCAgcGF0dGVybiA9ICIgRmVtYWxlfCBNYWxlIikpCgpkaXNjb25uZWN0aW9uICU8PiUgCiAgbXV0YXRlKEdlbmRlciA9IHN0cl9leHRyYWN0KEdyb3VwLCAiRmVtYWxlfE1hbGUiKSkgJT4lCiAgbXV0YXRlKEdlbmRlciA9IHJlcGxhY2VfbmEoR2VuZGVyLCByZXBsYWNlID0gIkdlbmRlcl9Ub3RhbCIpKQoKCiMjIyMgdGhpcyB2YXJpYWJsZSBzZWVtcyB1bm5lY2Nlc3NhcnkuLi4gdW5sZXNzIGZhY2V0aW5nIG1heWJlIGJ5IGl0IGxhdGVyPz8gT2sgaXQgaXMgdXNlZCBmb3IgYSBmaWd1cmUgdG8gb25seSBnZXQgcmFjZSB0b3RhbCBncm91cHMuLi4gdGhhdHMgYWxsIC0gaXQgaXMgYWxzbyBjb2RlZCB0aGlzIHdheSBmb3IgdGhlIGFzaWFuIHN1Ymdyb3Vwcy4uLgojIHRoaXMgY291bGQgZWFzaWx5IGJlIGRvbmUgdGhvdWdoIHVzaW5nIHNvbWUgZmlsdGVyIHN0ZXBzIGxpa2UgdGhpcy4uLiAKIyBkaXNjb25uZWN0aW9uICU+JQojICAgZmlsdGVyKEdlbmRlciA9PSAiR2VuZGVyX1RvdGFsIiwKIyAgICAgICAgICBHcm91cCAhPSAiVW5pdGVkIFN0YXRlcyIpCgojIGNvdWxkIHRoZW4gZG8gYnkgZ2VuZGVyLSBtYWxlcyBvZiBlYWNoIHJhY2UKI2Rpc2Nvbm5lY3Rpb24gJT4lCiNmaWx0ZXIoR2VuZGVyID09ICJNYWxlIiwKIyAgICAgICAgUmFjZSAhPSAiQWxsX3JhY2VzIikKCiMgZGlzY29ubmVjdGlvbiAlPD4lCiMgICBtdXRhdGUoVHlwZSA9IGNhc2Vfd2hlbigKIyAgICAgc3RyX2RldGVjdChHcm91cCwgIlVuaXRlZCBTdGF0ZXMiKSB+ICJVUyBUb3RhbCIsCiMgICAgIHN0cl9kZXRlY3QoR3JvdXAsICJGZW1hbGUiKSB+ICJHZW5kZXIgVG90YWwiLAojICAgICAgc3RyX2RldGVjdChHcm91cCwgIk1hbGUiKSB+ICJHZW5kZXIgVG90YWwiLAojICAgICBzdHJfZGV0ZWN0KEdyb3VwLCAiIEZlbWFsZXwgTWFsZSIpIH4gIlN1Ymdyb3VwIFRvdGFsIiwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+ICJSYWNlIFRvdGFsIikpCiAgICAgICAgICAgIAogICAgICAgICAKICAgICAgICAgICAKCmBgYAoKCmBgYHtyfQoKZGlzX2xvbmcgPC0gZGlzY29ubmVjdGlvbiAlPiUKICB0aWR5cjo6cGl2b3RfbG9uZ2VyKGNvbHMgPSBjb250YWlucygiMjAiKSwKICAgICAgICAgICAgICAgICAgbmFtZXNfdG8gPSAiWWVhciIsCiAgICAgICAgICAgICAgICAgdmFsdWVzX3RvID0gIlJhdGUiLAogICAgICAgICAgICAgIG5hbWVzX3ByZWZpeCA9ICJQZXJjXyIpICU+JQogIGRwbHlyOjptdXRhdGUoWWVhciA9IGFzLm51bWVyaWMoWWVhcikpCgpgYGAKCmBgYHtyfQpkZjEgPC0gZGYxICU+JQogIG11dGF0ZShHZW5kZXIgPSBkcGx5cjo6Y2FzZV93aGVuKAogICAgc3RyaW5ncjo6c3RyX2RldGVjdChHcm91cCwgIkZlbWFsZSIpIH4gVFJVRSwKICAgICAgc3RyaW5ncjo6c3RyX2RldGVjdChHcm91cCwgIk1hbGUiKSB+IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gTkEpLAogICAgICAgICBSYWNlID0gc3RyaW5ncjo6c3RyX3JlbW92ZV9hbGwoR3JvdXAsCiAgICAgICAgICAgICAgICBwYXR0ZXJuID0gcGFzdGUoYygiRmVtYWxlIiwiTWFsZSIsIlVuaXRlZFN0YXRlcyIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbGxhcHNlID0gInwiKSkpICU+JQogIG11dGF0ZShSYWNlID0gZHBseXI6Om5hX2lmKFJhY2UsICIiKSkKCmRmMSA8LSBkZjEgJT4lIAogIG11dGF0ZShUeXBlID0gY2FzZV93aGVuKGJhc2U6OmlzLm5hKEdlbmRlcikgJiAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhc2U6OmlzLm5hKFJhY2UpIH4gIlVTIFRvdGFsIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBiYXNlOjppcy5uYShHZW5kZXIpICYgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAhYmFzZTo6aXMubmEoUmFjZSkgfiAiUmFjZSBUb3RhbCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIWJhc2U6OmlzLm5hKEdlbmRlcikgJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgYmFzZTo6aXMubmEoUmFjZSkgfiAiR2VuZGVyIFRvdGFsIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gIlN1Ymdyb3VwIFRvdGFsIikpCgpkZjEgPC0gZGYxICU+JQogIG11dGF0ZShHZW5kZXIgPSBjYXNlX3doZW4oc3RyX2RldGVjdChHcm91cCwgIkZlbWFsZSIpIH4gIkZlbWFsZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0cl9kZXRlY3QoR3JvdXAsICJNYWxlIikgfiAiTWFsZSIpKQpgYGAKClRoZSBjb2x1bW5zIG9mIGBjaGFyYWN0ZXJgIGNsYXNzIGN1cnJlbnRseSBjb250YWluIHVwcGVyIGFuZCBsb3dlciBjYXNlIGNoYXJhY3RlcnMuIFdlIHdhbnQgdG8gZW5zdXJlIHRoYXQgd2UgdXNlIGEgY2FzZXMgY29uc2lzdGVudGx5IHRvIGVuc3VyZSB0aGF0IHRoZXJlIGFyZSBubyBlcnJvcnMgZHJpdmVuIGJ5IGNhc2Utc2Vuc2l0aXZlIGZ1bmN0aW9uIGRvd25zdHJlYW0uCgpUbyBkbyB0aGlzLCB3ZSB1c2UgdGhlIGBiYXNlOjp0b191cHBlcigpYCBmdW5jdGlvbi4gVGhpcyBmdW5jdGlvbiBtYWtlcyBhbGwgY2hhcmFjdGVycyB1cHBlcmNhc2UuCgpgYGB7cn0KZGYxIDwtIGRmMSAlPiUgCiAgbXV0YXRlX2lmKGlzLmNoYXJhY3RlciwgdG91cHBlcikKYGBgCgpGaW5hbGx5LCB3ZSBob21vZ2VuaXplIHRoZSBsYWJlbHMgYXNzaWduZWQgZm9yIGNlcnRhaW4gZ3JvdXBzLCBmaWxsIGluIG1pc3NpbmcgKGBOQWApIHZhbHVlcyB3aXRoIGEgc3RyaW5nLCBhbmQgcmVtb3ZlIGNvbHVtbnMgd2Ugbm8gbG9uZ2VyIG5lZWQgZnJvbSB0aGUgZGF0YWZyYW1lLiAKCmBgYHtyfQpkZjEgPC0gZGYxICU+JQogIG11dGF0ZShSYWNlID0gY2FzZV93aGVuKFJhY2UgPT0gIkxBVElOQSIgfiAiTEFUSU5PL0EiLAogICAgICAgICAgICAgICAgICAgICAgICAgIFJhY2UgPT0gIkxBVElOTyIgfiAiTEFUSU5PL0EiLAogICAgICAgICAgICAgICAgICAgICAgICAgIFJhY2UgPT0gIk5BVElWRUFNRVJJQ0FOIiB+ICJOQVRJVkUgQU1FUklDQU4iLAogICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiBSYWNlKSkgJT4lCiAgbXV0YXRlKEdlbmRlciA9IHRpZHlyOjpyZXBsYWNlX25hKEdlbmRlciwgIkFMTCIpLAogICAgICAgICBSYWNlID0gdGlkeXI6OnJlcGxhY2VfbmEoUmFjZSwgIkFMTCIpKSAlPiUKICBkcGx5cjo6c2VsZWN0KC1Hcm91cCkKYGBgCgpXZSBjYW4gcmVwZWF0IHRoaXMgcHJvY2VzcyBmb3IgdGhlIG90aGVyIHR3byB0YWJsZXMgbGlzdGVkIG9uIHBhZ2UgMzkuCgpMZXQncyBsb29rIGF0IHRoZSB0YWJsZSB3aXRob3V0IHRoZSBzcGVjaWFsIGZvcm1hdHRpbmcuCgpgYGB7cn0KaW1hZ2UyIDwtIGltYWdlX3JlYWQoaGVyZSgiaW1nIiwgImFzaWFuX3N1Ymdyb3Vwcy5wbmciKSkKaW1hZ2UyCmBgYAoKQXMgeW91IGNhbiBzZWUsIHRoZXJlIGFyZSBlbXB0eSBzcGFjZXMuIEFjY29yZGluZyB0byB0aGUgUERGLCB0aGVzZSBzcGFjZXMgYXJlIGVtcHR5IHRvIGRlbm90ZSB0aGF0IHRoZSBlc3RpbWF0ZXMgYXJlIHVucmVsaWFibGUuCgpUaGlzIG1heSBjYXVzZSBwcm9ibGVtcy4gV2hpdGVzcGFjZSBtdXN0IGJlIGhhbmRsZWQgZGlmZmVyZW50bHkuIFdlIG1heSBub3Qgd2FudCB0byBwcm9jZXNzIHRoZSBlbnRpcmUgaW1hZ2UgZm9yIHRoaXMgcmVhc29uLiAKCkluc3RlYWQsIHdlIGNhbiB1c2Ugc2VwYXJhdGUgaW1hZ2VzIHRvIGVuc3VyZSBhIHNpbXBsZXIgcHJvY2VzcyBsaWtlIHRoYXQgYWJvdmUuIAoKV2UgcmVhZCB0aGUgdGhyZWUgaW1hZ2VzLiAKYGBge3J9CmltYWdlMmEgPC0gaW1hZ2VfcmVhZChoZXJlKCJpbWciLCAiYXNpYW5fc3ViZ3JvdXBzQS5wbmciKSkKaW1hZ2UyYiA8LSBpbWFnZV9yZWFkKGhlcmUoImltZyIsICJhc2lhbl9zdWJncm91cHNCLnBuZyIpKQppbWFnZTJjIDwtIGltYWdlX3JlYWQoaGVyZSgiaW1nIiwgImFzaWFuX3N1Ymdyb3Vwc0MucG5nIikpCgptYWdpY2s6OmltYWdlX2luZm8oaW1hZ2UyYSkKbWFnaWNrOjppbWFnZV9pbmZvKGltYWdlMmIpCm1hZ2ljazo6aW1hZ2VfaW5mbyhpbWFnZTJjKQpgYGAKClRoZSBpbWFnZXMgbG9vayBsaWtlIHRoaXMuCgpgYGB7cn0KaW1hZ2UyYQppbWFnZTJiCmltYWdlMmMKYGBgCgpXZSBzYXZlIHRoZSB0ZXh0IGZyb20gdGhlIGltYWdlcyBpbnRvIG9iamVjdHMuCgpgYGB7cn0KZGYyYSA8LSBtYWdpY2s6OmltYWdlX29jcihpbWFnZTJhKQpkZjJiIDwtIG1hZ2ljazo6aW1hZ2Vfb2NyKGltYWdlMmIpCmRmMmMgPC0gbWFnaWNrOjppbWFnZV9vY3IoaW1hZ2UyYykKYGBgCgpXZSBwcm9jZXNzIHRoZXNlIG9iamVjdHMgc2VwYXJhdGVseS4gTm90ZSB0aGF0IHdlIHVzZSBhIHZlcnkgc2ltaWxhciBwcm9jZXNzIHRvIHRoYXQgZW1wbG95ZWQgaW4gdGhlIHdyYW5nbGluZyBvZiB0aGUgcHJldmlvdXMgdGFibGUuIAoKYGBge3J9CmRmMmEgPC0gZGYyYSAlPiUKICBzdHJzcGxpdCgiXG4iKSAlPiUKICB1bmxpc3QoKSAlPiUKICBhc190aWJibGUoKQoKZGYyYiA8LSBkZjJiICU+JQogIHN0cnNwbGl0KCJcbiIpICU+JQogIHVubGlzdCgpICU+JQogIGFzX3RpYmJsZSgpCgpkZjJjIDwtIGRmMmMgJT4lCiAgc3Ryc3BsaXQoIlxuIikgJT4lCiAgdW5saXN0KCkgJT4lCiAgYXNfdGliYmxlKCkKYGBgCgpXZSB0aGVuIGNvbWJpbmUgdGhlIG9iamVjdHMgd2l0aCB0aGUgYGRwbHlyOjpiaW5kX3Jvd3MoKWAgZnVuY3Rpb24uCgpUaGUgcHJvY2VzcyBpcyBub3cgdmVyeSBzaW1pbGFyIHRvIHRoZSBwcmV2aW91cyB0YWJsZS4KCjxzdHlsZT4KZGl2LnJlZCB7IGJhY2tncm91bmQtY29sb3I6I2ZmY2NjYjsgYm9yZGVyLXJhZGl1czogNXB4OyBwYWRkaW5nOiAyMHB4O30KPC9zdHlsZT4KPGRpdiBjbGFzcyA9ICJyZWQiPgoKKipNSUNIQUVMIE9OVElWRVJPUyoqCgoqSSB1c2VkIGJhc2UgUiB0byByZW1vdmUgdGhlIGZpcnN0IHRocmVlIHJvd3Mgb2YgYSBkYXRhZnJhbWUgaW4gdGhlIGZvbGxvd2luZyBjaHVuay4gSSBhbSBub3QgYXdhcmUgb2YgYSB0aWR5dmVyc2Ugc29sdXRpb24gZm9yIHRoaXM7IEkgYW0gc3VyZSBvbmUgZXhpc3RzLioKPC9kaXY+CgpgYGB7cn0KZGYyIDwtIGJpbmRfcm93cyhkZjJhLAogICAgICAgICAgZGYyYiwKICAgICAgICAgIGRmMmMpCgpkZjIgPC0gZGYyICU+JQogIGRwbHlyOjpzZWxlY3QodmFsdWUpICU+JQogIHB1bGwodmFsdWUpICU+JQogIHN0cl9zcGxpdCgiICIpCgpkZjJiIDwtIG1hcChkZjIsIHRhaWwsIDIpICU+JQogIG1hcCh+Z3N1YigiWyxdK3xbLl0rIiwgIiIsLikpICU+JQogIGRvLmNhbGwocmJpbmQsLikgJT4lCiAgZGF0YS5mcmFtZSgpICU+JQogIG11dGF0ZV9pZihpcy5jaGFyYWN0ZXIsIGFzLm51bWVyaWMpICU+JQogIG11dGF0ZV9hdCh2YXJzKC1YMiksIH4gLiAqIDAuMSkgJT4lCiAgdGliYmxlKCkgCgpkZjJhIDwtIGRmMiAlPiUKICBtYXAofnBhc3RlKC4sY29sbGFwc2UgPSAiIikpICU+JQogIG1hcCh+Z3N1YigiW1s6ZGlnaXQ6XV0rfFtbOnB1bmN0Ol1dKyIsICIiLC4pKSAlPiUKICBkby5jYWxsKHJiaW5kLC4pICU+JQogIGRhdGEuZnJhbWUoKSAlPiUKICB0aWJibGUoKQoKZGYyIDwtIGJpbmRfY29scyhkZjJhLCBkZjJiKQoKbmFtZXMoZGYyKSA8LSBjKCkKCmNvbHVtbl9uYW1lcyA8LSBjKCJHcm91cCIsCiAgICAgICAgICAgICAgICAgICJSYXRlIiwKICAgICAgICAgICAgICAgICAgIk5fMjAxNyIpCgpjb2xuYW1lcyhkZjIpIDwtIGNvbHVtbl9uYW1lcwoKZGYyIDwtIGRmMiAlPiUKICBkcGx5cjo6c2VsZWN0KC1OXzIwMTcpCgpkZjIgPC0gZGYyICU+JQogIGRwbHlyOjptdXRhdGUoWWVhciA9IDIwMTcpCgpkZjIgPC0gZGYyICU+JQogIG11dGF0ZShHZW5kZXIgPSBjYXNlX3doZW4oc3RyX2RldGVjdChHcm91cCwgIkZlbWFsZSIpIH4gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0cl9kZXRlY3QoR3JvdXAsICJNYWxlIikgfiBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiBOQSksCiAgICAgICAgIFN1Ymdyb3VwID0gc3RyX3JlbW92ZV9hbGwoR3JvdXAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGF0dGVybiA9IHBhc3RlKGMoIkZlbWFsZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk1hbGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJBU0lBTiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkFzaWFuIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sbGFwc2UgPSAifCIpKSkgJT4lCiAgbXV0YXRlKFN1Ymdyb3VwID0gbmFfaWYoU3ViZ3JvdXAsICIiKSkKCmdsaW1wc2UoZGYyKQoKZGYyIDwtIGRmMlstKDE6MyksXQoKZGYyIDwtIGRmMiAlPiUgCiAgbXV0YXRlKFR5cGUgPSBjYXNlX3doZW4oaXMubmEoR2VuZGVyKSAmIGlzLm5hKFN1Ymdyb3VwKSB+ICJBc2lhbiBUb3RhbCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgaXMubmEoR2VuZGVyKSAmICFpcy5uYShTdWJncm91cCkgfiAiU3ViZ3JvdXAgVG90YWwiLAogICAgICAgICAgICAgICAgICAgICAgICAgICFpcy5uYShHZW5kZXIpICYgaXMubmEoU3ViZ3JvdXApIH4gIkdlbmRlciBUb3RhbCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+ICJTdWJncm91cCBUb3RhbCIpKQoKZ2xpbXBzZShkZjIpCgpkZjIgPC0gZGYyICU+JQogIG11dGF0ZShHZW5kZXIgPSBjYXNlX3doZW4oc3RyX2RldGVjdChHcm91cCwgIkZlbWFsZSIpIH4gIkZlbWFsZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdHJfZGV0ZWN0KEdyb3VwLCAiTWFsZSIpIH4gIk1hbGUiKSkKCmRmMiA8LSBkZjIgJT4lIAogIG11dGF0ZV9pZihpcy5jaGFyYWN0ZXIsIHRvbG93ZXIpICU+JQogIG11dGF0ZV9pZihpcy5jaGFyYWN0ZXIsIHRvdXBwZXIpCgpkZjIgPC0gZGYyICU+JQogIG11dGF0ZShHZW5kZXIgPSByZXBsYWNlX25hKEdlbmRlciwgIkFMTCIpLAogICAgICAgICBTdWJncm91cCA9IHJlcGxhY2VfbmEoU3ViZ3JvdXAsICJBTEwiKSkgJT4lCiAgZHBseXI6OnNlbGVjdCgtR3JvdXApICU+JQogIG11dGF0ZShTdWJncm91cCkKCmRmMiA8LSBkZjIgJT4lCiAgbXV0YXRlKFN1Ymdyb3VwID0gY2FzZV93aGVuKFN1Ymdyb3VwID09ICJUV09PUk1PUkUiIH4gIlRXTyBPUiBNT1JFIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+IFN1Ymdyb3VwKSkKYGBgCgpOb3RlIHRoYXQgd2UgdG9vayBhIHByb2Nlc3MgdGhhdCBoYWQgc3VjY2Vzc2Z1bGx5IHdvcmtlZCBmb3IgdXMgYW5kIG1vZGlmaWVkIGl0IHNsaWdodGx5IGZvciBzZXBhcmF0ZSwgc2ltaWxhcmx5LXNvdXJjZWQgZGF0YS4gCgpUaGlzIGlzIGEgY29tbW9uIGFwcHJvYWNoIGluIGRhdGEgc2NpZW5jZS4gT2Z0ZW4sIHRoZSBkdXJhdGlvbiBvZiB0aGUgd3JhbmdsaW5nIHByb2Nlc3MgY2FuIGxpbWl0IHRoZSBkZXB0aCBvZiBhbiBhbmFseXNpcyBmb3IgcHJhY3RpY2FsIHJlYXNvbnMuIFVzaW5nIHRyaWVkIG1ldGhvZHMgY2FuIGhlbHAgcmVkdWNlIHRoZSB0aW1lIG5lZWRlZCB0byB3cmFuZ2xlIGRhdGEgYW5kIGFsbG93IHRpbWUgZm9yIG90aGVyIHBhcnRzIG9mIGFuIGFuYWx5c2lzLiAKCkxldCdzIGFkZCB0aGUgMjAxOCBkYXRhIGZvciB0aGlzIGdyb3VwLgoKV2UgaW1wb3J0IHRoZSBpbWFnZS4gCgpgYGB7cn0KaW1hZ2U1IDwtIGltYWdlX3JlYWQoaGVyZSgiaW1nIiwgImFzaWFuX3N1Ymdyb3Vwc18yMDE4LnBuZyIpKQoKZGYyXzIwMTggPC0gbWFnaWNrOjppbWFnZV9vY3IoaW1hZ2U1KQpgYGAKCkFzIHlvdSBjYW4gc2VlLCB3ZSBoYXZlIHJlcGVhdGVkIG5ld2xpbmVzIChgXG5gKS4gV2UgY2FuIHJlbW92ZSB0aGVzZSB3aXRoIHNvbWUgc2ltcGxleCByZWdleC4KCmBgYHtyfQpkZjJfMjAxOCA8LSBnc3ViKCcoW1xuXSlcXDErJywKICAgICAgICAgICAgICAgICAnXFwxJywKICAgICAgICAgICAgICAgICBkZjJfMjAxOCkKCmRmMl8yMDE4IDwtIGdzdWIoIltbOnB1bmN0Ol1dKyIsCiAgICAgICAgICAgICAgICAgIiIsCiAgICAgICAgICAgICAgICAgZGYyXzIwMTgpCgpkZjJfMjAxOCA8LSBnc3ViKCIgaSAiLAogICAgICAgICAgICAgICAgICIiLAogICAgICAgICAgICAgICAgIGRmMl8yMDE4KQpgYGAKCldlIHByb2NlZWQsIG1ha2luZyBzbGlnaHQgbW9kaWZpY2F0aW9ucyB0byB0aGUgcHJvY2VzcyBhcyBuZWVkZWQuCgpUaGUgYm9sZCBmb250IGFwcGVhcnMgdG8gaGF2ZSBjYXVzZWQgYSB0eXBvcy4gCgpgYGB7cn0KZGYyXzIwMTggJT4lCiAgc3Ryc3BsaXQoIlxuIikgJT4lCiAgdW5saXN0KCkgJT4lCiAgYXNfdGliYmxlKCkKYGBgCgpXZSBmaXggdGhlIHR5cG9zLgoKYGBge3J9CmRmMl8yMDE4IDwtIGRmMl8yMDE4ICU+JQogIHN0cnNwbGl0KCJcbiIpICU+JQogIHVubGlzdCgpICU+JQogIGdzdWIoIiBCNDQgIiwiNTQiLC4pICU+JQogIGdzdWIoIldvbWVuNzQiLCJXb21lbiA3NCIsLikgJT4lCiAgZ3N1YigiSE1PTkcxMDIiLCJITU9ORyAxMDIiLC4pICU+JQogIGFzX3RpYmJsZSgpCgpkZjJfMjAxOCAlPiUKICBwcmludCguLG4gPSBkaW0oLilbMV0pCmBgYAoKV2UgdGhlbiBjb250aW51ZSBhcyB3ZSB3b3VsZCBub3JtYWxseS4gCgpgYGB7cn0KZGYyXzIwMTggPC0gZGYyXzIwMTggJT4lCiAgZHBseXI6OnNlbGVjdCh2YWx1ZSkgJT4lCiAgcHVsbCh2YWx1ZSkgJT4lCiAgc3RyX3NwbGl0KCIgIikKCmRmMl8yMDE4IDwtIGxhcHBseShkZjJfMjAxOCwKICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uKHgpIHhbbmNoYXIoeCkgPj0gMV0pCgpkZjJhXzIwMTggPC0gZGYyXzIwMTggJT4lCiAgbWFwKH5wYXN0ZSguLGNvbGxhcHNlID0gIiIpKSAlPiUKICBtYXAofmdzdWIoIltbOmRpZ2l0Ol1dK3xbWzpwdW5jdDpdXSsiLCAiIiwuKSkgJT4lCiAgZG8uY2FsbChyYmluZCwuKSAlPiUKICBkYXRhLmZyYW1lKCkgJT4lCiAgdGliYmxlKCkKCmRmMmJfMjAxOCA8LSBtYXAoZGYyXzIwMTgsIHRhaWwsIDIpICU+JQogIGRvLmNhbGwocmJpbmQsLikgJT4lCiAgZGF0YS5mcmFtZSgpICU+JQogIG11dGF0ZV9pZihpcy5jaGFyYWN0ZXIsIGFzLm51bWVyaWMpICU+JQogIG11dGF0ZV9hdCh2YXJzKC1YMiksIH4gLiAqIDAuMSkgJT4lCiAgdGliYmxlKCkgCgpybShkZjJfMjAxOCkKICAKZGYyXzIwMTggPC0gYmluZF9jb2xzKGRmMmFfMjAxOCwKICAgICAgICAgICAgICAgICAgICAgIGRmMmJfMjAxOCkKbmFtZXMoZGYyXzIwMTgpIDwtIGMoKQoKY29sdW1uX25hbWVzIDwtIGMoIkdyb3VwIiwKICAgICAgICAgICAgICAgICAgIlJhdGUiLAogICAgICAgICAgICAgICAgICAiTl8yMDE3IikKCmNvbG5hbWVzKGRmMl8yMDE4KSA8LSBjb2x1bW5fbmFtZXMKCmRmMl8yMDE4IDwtIGRmMl8yMDE4ICU+JQogIGRwbHlyOjpzZWxlY3QoLU5fMjAxNykKCmRmMl8yMDE4IDwtIGRmMl8yMDE4ICU+JQogIGRwbHlyOjptdXRhdGUoWWVhciA9IDIwMTgpCgpkZjJfMjAxOCA8LSBkZjJfMjAxOCAlPiUKICBtdXRhdGUoR2VuZGVyID0gY2FzZV93aGVuKHN0cl9kZXRlY3QoR3JvdXAsICJXb21lbiIpIH4gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0cl9kZXRlY3QoR3JvdXAsICJNZW4iKSB+IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+IE5BKSkKCmxhYmVscyA8LSB1bmxpc3QoZGYyXzIwMThbYyhzZXEoMSwxNSwgYnk9MyksMTYsMTcpLDFdLCB1c2UubmFtZXMgPSBGQUxTRSkKCmRpbShkZjJfMjAxOClbMV0KCmxhYmVsc18zIDwtIGMocmVwKGxhYmVsc1sxOjVdLCBlYWNoID0gZGltKGRmMl8yMDE4KVsxXS8obGVuZ3RoKGxhYmVscyktMikpLAogICAgICAgICAgICAgICJITU9ORyIsCiAgICAgICAgICAgICAgIkNBTUJPRElBTiIpCgpkZjJfMjAxOCRTdWJncm91cCA8LSBsYWJlbHNfMwoKZGYyXzIwMTggPC0gZGYyXzIwMTggJT4lIAogIG11dGF0ZShUeXBlID0gIlN1Ymdyb3VwIFRvdGFsIikKCmdsaW1wc2UoZGYyXzIwMTgpCgpkZjJfMjAxOCA8LSBkZjJfMjAxOCAlPiUKICBtdXRhdGUoR2VuZGVyID0gY2FzZV93aGVuKEdlbmRlciA9PSBUUlVFIH4gIkZlbWFsZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBHZW5kZXIgPT0gRkFMU0UgfiAiTWFsZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gIkFsbCIpKQoKZGYyXzIwMTggPC0gZGYyXzIwMTggJT4lIAogIG11dGF0ZV9pZihpcy5jaGFyYWN0ZXIsIHRvbG93ZXIpICU+JQogIG11dGF0ZV9pZihpcy5jaGFyYWN0ZXIsIHRvdXBwZXIpCgpkZjJfMjAxOCA8LSBkZjJfMjAxOCAlPiUKICBkcGx5cjo6c2VsZWN0KC1Hcm91cCkKYGBgCgpUaGUgZGF0YWZyYW1lIHdlIHByb2R1Y2VkIGRvZXMgbm90IGNvbnRhaW4gdG90YWxzLiAKCmBgYHtyfQpkZjJfMjAxOCAlPiUKICBwcmludCguLCBuID0gZGltKC4pWzFdKQpgYGAKCldlIGNhbiBmaW5kIHRoZXNlIHRvdGFscyBpbiB0aGUgUERGIGRpcmVjdGx5IGFuZCBjcmVhdGUgcm93cyBhcyBuZWVkZWQKCldlIGxvYWQgdGhlIFBERi4KCmBgYHtyfQpleGNlcnB0IDwtIGltYWdlX3JlYWQoaGVyZSgiaW1nIiwgImFzaWFuX3lvdXRoX2V4Y2VycHQucG5nIikpCgpleGNlcnB0CmBgYAoKV2UgYWRkIHRoZSByb3dzLgoKYGBge3J9CmRmMl8yMDE4IDwtIGRmMl8yMDE4ICU+JQogIGFkZF9yb3coUmF0ZSA9IDYuMiwKICAgICAgICAgIFllYXIgPSAyMDE4LAogICAgICAgICAgR2VuZGVyID0gIkFMTCIsCiAgICAgICAgICBTdWJncm91cCA9ICJBTEwiLCAKICAgICAgICAgIFR5cGUgPSAiQVNJQU4gVE9UQUwiKSAlPiUKICBhZGRfcm93KFJhdGUgPSA2LjEsCiAgICAgICAgICBZZWFyID0gMjAxOCwKICAgICAgICAgIEdlbmRlciA9ICJGRU1BTEUiLAogICAgICAgICAgU3ViZ3JvdXAgPSAiQUxMIiwgCiAgICAgICAgICBUeXBlID0gIkdFTkRFUiBUT1RBTCIpICU+JQogIGFkZF9yb3coUmF0ZSA9IDYuNCwKICAgICAgICAgIFllYXIgPSAyMDE4LAogICAgICAgICAgR2VuZGVyID0gIk1BTEUiLAogICAgICAgICAgU3ViZ3JvdXAgPSAiQUxMIiwgCiAgICAgICAgICBUeXBlID0gIkdFTkRFUiBUT1RBTCIpCmBgYAoKYGBge3J9CmRmMiA8LSBiaW5kX3Jvd3MoZGYyLAogICAgICAgICAgICAgICAgIGRmMl8yMDE4KQpgYGAKCldlIHJlcGVhdCB0aGlzIHByb2Nlc3MgYWdhaW4gZm9yIExhdGluby9hIHN1Ymdyb3Vwcy4gCgpUaGUgdGFibGUsIHdpdGhvdXQgdGhlIHNwZWNpYWwgZm9ybWF0dGluZywgbG9va3MgbGlrZSB0aGlzLgoKYGBge3J9CmltYWdlMyA8LSBpbWFnZV9yZWFkKGhlcmUoImltZyIsICJsYXRpbm9fYV9zdWJncm91cHMucG5nIikpCmBgYAoKVGhlcmUgYXJlIG5vIHdoaXRlc3BhY2VzIGluIHRoaXMgdGFibGUuCgpXZSBwcm9jZWVkIHVzaW5nIHdoYXQgd2UndmUgbGVhcm5lZCB3aGlsZSB3cmFuZ2xpbmcgdGhlIGZpcnN0IHR3byB0YWJsZXMuCgpgYGB7cn0KZGYzIDwtIG1hZ2ljazo6aW1hZ2Vfb2NyKGltYWdlMykKCmRmMyAlPiUKICBiYXNlOjpzdHJzcGxpdCgiXG4iKSAlPiUKICBiYXNlOjp1bmxpc3QoKSAlPiUKICB0aWJibGU6OmFzX3RpYmJsZSgpCmBgYAoKV2UgYXJlIG9mdGVuIHByZXNlbnRlZCB3aXRoIHNjZW5hcmlvcyB3aGVyZSBzdGFuZC1hbG9uZSBhcHByb2FjaGVzIGFyZSBkaWZmaWN1bHQgb3IgdGltZS1jb25zdW1pbmcuCgpJdCBpcyBhbHdheXMgYmVzdCB0byBkb2N1bWVudCB0aGUgc3RlcHMgdGFrZSB0byByZXNwb25kIHRvIHRoZXNlIHNjZW5hcmlvcy4gV3JhbmdsaW5nIHRoaXMgdGhpcmQgdGFibGUgaXMgYSBwcmltZSBleGFtcGxlIG9mIHRoaXMuIAoKV2UgYXJlIG1pc3NpbmcgYSByb3cuIExldCdzIG1hbnVhbGx5IGFkZCB0aGUgcm93LgoKYGBge3J9CmRmMyA8LSBkZjMgJT4lCiAgc3Ryc3BsaXQoIlxuIikgJT4lCiAgdW5saXN0KCkgJT4lCiAgYXNfdGliYmxlKCkKCmRmMyA8LSBkZjMgJT4lCiAgcmJpbmQoIlBSLCBEUiwgQ3ViYW4gMTUuMSAyMTEsMjAwIikKYGBgCgpXZSBjYW4gbm93IHByb2NlZWQgYXMgd2UgZGlkIHdpdGggdGhlIHByZXZpb3VzIHRhYmxlcy4gCgpgYGB7cn0KZGYzIDwtIGRmMyAlPiUKICBkcGx5cjo6c2VsZWN0KHZhbHVlKSAlPiUKICBwdWxsKHZhbHVlKSAlPiUKICBzdHJfc3BsaXQoIiAiKQoKZGYzYiA8LSBtYXAoZGYzLCB0YWlsLCAyKSAlPiUKICBtYXAofmdzdWIoIlssXSt8Wy5dKyIsICIiLC4pKSAlPiUKICBkby5jYWxsKHJiaW5kLC4pICU+JQogIGRhdGEuZnJhbWUoKSAlPiUKICBtdXRhdGVfaWYoaXMuY2hhcmFjdGVyLCBhcy5udW1lcmljKSAlPiUKICBtdXRhdGVfYXQodmFycygtWDIpLCB+IC4gKiAwLjEpICU+JQogIHRpYmJsZSgpIAoKZGYzYSA8LSBkZjMgJT4lCiAgbWFwKH5wYXN0ZSguLGNvbGxhcHNlID0gIiIpKSAlPiUKICBtYXAofmdzdWIoIltbOmRpZ2l0Ol1dK3xbWzpwdW5jdDpdXSsiLCAiIiwuKSkgJT4lCiAgZG8uY2FsbChyYmluZCwuKSAlPiUKICBkYXRhLmZyYW1lKCkgJT4lCiAgdGliYmxlKCkKCnJtKGRmMykKICAKZGYzIDwtIGJpbmRfY29scyhkZjNhLCBkZjNiKQpuYW1lcyhkZjMpIDwtIGMoKQoKY29sdW1uX25hbWVzIDwtIGMoIkdyb3VwIiwKICAgICAgICAgICAgICAgICAgIlJhdGUiLAogICAgICAgICAgICAgICAgICAiTl8yMDE3IikKCmNvbG5hbWVzKGRmMykgPC0gY29sdW1uX25hbWVzCgpgYGAKCklmIHdlIGxvb2sgYXQgdGhlIGxhc3QgZmV3IHJvd3MsIHdlIHNlZSB0aGF0IHRoZXJlIGlzIGEgdHlwby4gVGhlcmUgYXJlIHR3byBmZW1hbGUgZ3JvdXBzLgoKYGBge3J9CnRhaWwoZGYzKQpgYGAKClNvbWV0aW1lcyB3aGVuIHdyYW5nbGluZyB0ZXh0IGRhdGEsIHdlIHdpbGwgY29tZSBhY3Jvc3MgYSB0eXBvLiBXZSBuZWVkIHRvIGRldGVybWluZSBob3cgdG8gcmVzcG9uZCB0byB0aGUgdHlwbyBhbmQgbWFrZSBub3RlIG9mIGl0LiBJdCdzIG9mdGVuIGJlc3QgdG8gY29uc3VsdCBhIHNlY29uZGFyeSBzb3VyY2UgdG8gY29uZmlybSB0aGF0IGNoYW5nZXMgbWFkZSBhcmUgYWNjdXJhdGUuIAoKRm9yIHRoZSBwdXJwb3NlcyBvZiB0aGlzIGNhc2Ugc3R1ZHksIHdlIHdpbGwgYXNzdW1lIHRoYXQgdGhlIGZpcnN0IG9mIHRoZSB0d28gcm93cyByZXByZXNlbnRzIG1hbGUgZGlzY29ubmVjdGlvbiByYXRlcyBpbiB0aGUgTGF0aW5vL2Egc3ViZ3JvdXA7IHRoaXMgd291bGQgYmUgY29uc2lzdGVudCB3aXRoIHRoZSBvcmRlcmluZyBvZiBnZW5kZXJzIGluIHRoZSBwcmV2aW91cyBzdWJncm91cHMuIAoKTGV0J3MgbWFrZSB0aGUgY29ycmVjdGlvbiB0byB0aGUgdHlwby4KCmBgYHtyfQpkZjMgPC0gZGYzICU+JQogIG11dGF0ZShHcm91cCA9IGNhc2Vfd2hlbihHcm91cCA9PSAiUFJEUkN1YmFuRmVtYWxlIiAmIE5fMjAxNyA9PSAxMTQ1MDAgfiAiUFJEUkN1YmFuTWFsZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gR3JvdXApKQpgYGAKCkl0IGxvb2tzIGxpa2Ugd2UndmUgc3VjY2VzZnVsbHkgY29ycmVjdGVkIHRoZSB0eXBvLgoKYGBge3J9CnRhaWwoZGYzKQpgYGAKCldlIGNhbiBjb250aW51ZSB3aXRoIHRoZSBwcm9jZXNzIHdlJ3ZlIGRldmVsb3BlZCBub3cgdGhhdCB3ZSBoYXZlIG1hZGUgdGhlIGNvcnJlY3Rpb24uCgpgYGB7cn0KZGYzIDwtIGRmMyAlPiUKICBkcGx5cjo6c2VsZWN0KC1OXzIwMTcpCgpkZjMgPC0gZGYzICU+JQogIGRwbHlyOjptdXRhdGUoWWVhciA9IDIwMTcpCgpkZjMgPC0gZGYzICU+JQogIG11dGF0ZShHZW5kZXIgPSBjYXNlX3doZW4oc3RyX2RldGVjdChHcm91cCwgIkZlbWFsZSIpIH4gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0cl9kZXRlY3QoR3JvdXAsICJNYWxlIikgfiBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiBOQSksCiAgICAgICAgIFN1Ymdyb3VwID0gc3RyX3JlbW92ZV9hbGwoR3JvdXAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGF0dGVybiA9IHBhc3RlKGMoIkZlbWFsZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk1hbGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJMQVRJTk8iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJMYXRpbm8iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJMYXRpbmEiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xsYXBzZSA9ICJ8IikpKSAlPiUKICBtdXRhdGUoU3ViZ3JvdXAgPSBuYV9pZihTdWJncm91cCwgIiIpKQoKZ2xpbXBzZShkZjMpCgpkZjMgPC0gZGYzICU+JSAKICBtdXRhdGUoVHlwZSA9IGNhc2Vfd2hlbihpcy5uYShHZW5kZXIpICYgaXMubmEoU3ViZ3JvdXApIH4gIkxhdGluby9hIFRvdGFsIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBpcy5uYShHZW5kZXIpICYgIWlzLm5hKFN1Ymdyb3VwKSB+ICJTdWJncm91cCBUb3RhbCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIWlzLm5hKEdlbmRlcikgJiBpcy5uYShTdWJncm91cCkgfiAiR2VuZGVyIFRvdGFsIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gIlN1Ymdyb3VwIFRvdGFsIikpCgpnbGltcHNlKGRmMykKCmRmMyA8LSBkZjMgJT4lCiAgbXV0YXRlKEdlbmRlciA9IGNhc2Vfd2hlbihzdHJfZGV0ZWN0KEdyb3VwLCAiRmVtYWxlIikgfiAiRmVtYWxlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0cl9kZXRlY3QoR3JvdXAsICJNYWxlIikgfiAiTWFsZSIpKQoKZGYzIDwtIGRmMyAlPiUgCiAgbXV0YXRlX2lmKGlzLmNoYXJhY3RlciwgdG9sb3dlcikgJT4lCiAgbXV0YXRlX2lmKGlzLmNoYXJhY3RlciwgdG91cHBlcikKCmRmMyA8LSBkZjMgJT4lCiAgbXV0YXRlKEdlbmRlciA9IHJlcGxhY2VfbmEoR2VuZGVyLCAiQUxMIiksCiAgICAgICAgIFN1Ymdyb3VwID0gcmVwbGFjZV9uYShTdWJncm91cCwgIkFMTCIpKSAlPiUKICBkcGx5cjo6c2VsZWN0KC1Hcm91cCkgJT4lCiAgbXV0YXRlKFN1Ymdyb3VwKQoKZGYzIDwtIGRmMyAlPiUKICBtdXRhdGUoU3ViZ3JvdXAgPSBjYXNlX3doZW4oU3ViZ3JvdXAgPT0gIlNPVVRIQU1FUklDQU4iIH4gIlNPVVRIIEFNRVJJQ0FOIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgU3ViZ3JvdXAgPT0gIkNFTlRSQUxBTUVSSUNBTiIgfiAiQ0VOVFJBTCBBTUVSSUNBTiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFN1Ymdyb3VwID09ICJQUkRSQ1VCQU4iIH4gIlBSL0RSL0NVQkFOIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+IFN1Ymdyb3VwKSkKYGBgCgpMZXQncyBhZGQgdGhlIDIwMTggZGF0YSB0byB0aGlzIGRhdGFmcmFtZS4KCldlIGltcG9ydCB0aGUgaW1hZ2UuIAoKYGBge3J9CmltYWdlNSA8LSBpbWFnZV9yZWFkKGhlcmUoImltZyIsICJsYXRpbm9fYV9zdWJncm91cHNfMjAxOC5wbmciKSkKCmRmM18yMDE4IDwtIG1hZ2ljazo6aW1hZ2Vfb2NyKGltYWdlNSkKYGBgCgpBcyB5b3UgY2FuIHNlZSwgd2UgaGF2ZSByZXBlYXRlZCBuZXdsaW5lcyAoYFxuYCkuIFdlIGNhbiByZW1vdmUgdGhlc2Ugd2l0aCBzb21lIHNpbXBsZXggcmVnZXguCgpgYGB7cn0KZGYzXzIwMTggPC0gZ3N1YignKFtcbl0pXFwxKycsCiAgICAgICAgICAgICAgICAgJ1xcMicsCiAgICAgICAgICAgICAgICAgZGYzXzIwMTgpCgpkZjNfMjAxOCA8LSBnc3ViKCJbWzpwdW5jdDpdXSsiLAogICAgICAgICAgICAgICAgICIiLAogICAgICAgICAgICAgICAgIGRmM18yMDE4KQpgYGAKCldlIHByb2NlZWQsIG1ha2luZyBzbGlnaHQgbW9kaWZpY2F0aW9ucyB0byB0aGUgcHJvY2VzcyBhcyBuZWVkZWQuCgpgYGB7cn0KZGYzXzIwMTggPC0gZGYzXzIwMTggJT4lCiAgc3Ryc3BsaXQoIlxuIikgJT4lCiAgdW5saXN0KCkgJT4lCiAgYXNfdGliYmxlKCkKCmRmM18yMDE4IDwtIGRmM18yMDE4ICU+JQogIGRwbHlyOjpzZWxlY3QodmFsdWUpICU+JQogIHB1bGwodmFsdWUpICU+JQogIHN0cl9zcGxpdCgiICIpCgpkZjNfMjAxOCA8LSBsYXBwbHkoZGYzXzIwMTgsCiAgICAgICAgICAgICAgICAgICBmdW5jdGlvbih4KSB4W25jaGFyKHgpID49IDFdKQoKZGYzYV8yMDE4IDwtIGRmM18yMDE4ICU+JQogIG1hcCh+cGFzdGUoLixjb2xsYXBzZSA9ICIiKSkgJT4lCiAgbWFwKH5nc3ViKCJbWzpkaWdpdDpdXSt8W1s6cHVuY3Q6XV0rIiwgIiIsLikpICU+JQogIGRvLmNhbGwocmJpbmQsLikgJT4lCiAgZGF0YS5mcmFtZSgpICU+JQogIHRpYmJsZSgpCgpkZjNiXzIwMTggPC0gbWFwKGRmM18yMDE4LCB0YWlsLCAyKSAlPiUKICBkby5jYWxsKHJiaW5kLC4pICU+JQogIGRhdGEuZnJhbWUoKSAlPiUKICBtdXRhdGVfaWYoaXMuY2hhcmFjdGVyLCBhcy5udW1lcmljKSAlPiUKICBtdXRhdGVfYXQodmFycygtWDIpLCB+IC4gKiAwLjEpICU+JQogIHRpYmJsZSgpIAoKcm0oZGYzXzIwMTgpCiAgCmRmM18yMDE4IDwtIGJpbmRfY29scyhkZjNhXzIwMTgsCiAgICAgICAgICAgICAgICAgICAgICBkZjNiXzIwMTgpCm5hbWVzKGRmM18yMDE4KSA8LSBjKCkKCmNvbHVtbl9uYW1lcyA8LSBjKCJHcm91cCIsCiAgICAgICAgICAgICAgICAgICJSYXRlIiwKICAgICAgICAgICAgICAgICAgIk5fMjAxNyIpCgpjb2xuYW1lcyhkZjNfMjAxOCkgPC0gY29sdW1uX25hbWVzCgpkZjNfMjAxOCA8LSBkZjNfMjAxOCAlPiUKICBkcGx5cjo6c2VsZWN0KC1OXzIwMTcpCgpkZjNfMjAxOCA8LSBkZjNfMjAxOCAlPiUKICBkcGx5cjo6bXV0YXRlKFllYXIgPSAyMDE4KQoKZGYzXzIwMTggPC0gZGYzXzIwMTggJT4lCiAgbXV0YXRlKEdlbmRlciA9IGNhc2Vfd2hlbihzdHJfZGV0ZWN0KEdyb3VwLCAiV29tZW4iKSB+IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdHJfZGV0ZWN0KEdyb3VwLCAiTWVuIikgfiBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiBOQSkpCgpsYWJlbHMgPC0gdW5saXN0KGRmM18yMDE4W3NlcSgxLDEyLCBieSA9MyksMV0sIHVzZS5uYW1lcyA9IEZBTFNFKQoKZGltKGRmM18yMDE4KVsxXQoKbGFiZWxzXzMgPC0gcmVwKGxhYmVscywgZWFjaCA9IGRpbShkZjNfMjAxOClbMV0vbGVuZ3RoKGxhYmVscykpCgpkZjNfMjAxOCRTdWJncm91cCA8LSBsYWJlbHNfMwoKZGYzXzIwMTggPC0gZGYzXzIwMTggJT4lIAogIG11dGF0ZShUeXBlID0gIlN1Ymdyb3VwIFRvdGFsIikKCmdsaW1wc2UoZGYzXzIwMTgpCgpkZjNfMjAxOCA8LSBkZjNfMjAxOCAlPiUKICBtdXRhdGUoR2VuZGVyID0gY2FzZV93aGVuKEdlbmRlciA9PSBUUlVFIH4gIkZlbWFsZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBHZW5kZXIgPT0gRkFMU0UgfiAiTWFsZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gIkFsbCIpKQoKZGYzXzIwMTggPC0gZGYzXzIwMTggJT4lIAogIG11dGF0ZV9pZihpcy5jaGFyYWN0ZXIsIHRvbG93ZXIpICU+JQogIG11dGF0ZV9pZihpcy5jaGFyYWN0ZXIsIHRvdXBwZXIpCgpkZjNfMjAxOCA8LSBkZjNfMjAxOCAlPiUKICBkcGx5cjo6c2VsZWN0KC1Hcm91cCkKCmRmM18yMDE4IDwtIGRmM18yMDE4ICU+JQogIG11dGF0ZShTdWJncm91cCA9IGNhc2Vfd2hlbihTdWJncm91cCA9PSAiU09VVEhBTUVSSUNBTiIgfiAiU09VVEggQU1FUklDQU4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBTdWJncm91cCA9PSAiQ0VOVFJBTEFNRVJJQ0FOIiB+ICJDRU5UUkFMIEFNRVJJQ0FOIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgU3ViZ3JvdXAgPT0gIlBSRFJDVUJBTiIgfiAiUFIvRFIvQ1VCQU4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gU3ViZ3JvdXApKQpgYGAKCldlIGxvYWQgdGhlIFBERi4KCmBgYHtyfQpybShleGNlcnB0KQpleGNlcnB0IDwtIGltYWdlX3JlYWQoaGVyZSgiaW1nIiwgImxhdGlub19hX3lvdXRoX2V4Y2VycHQucG5nIikpCgpleGNlcnB0CmBgYAoKV2UgYWRkIHRoZSByb3dzLgoKYGBge3J9CmRmM18yMDE4IDwtIGRmM18yMDE4ICU+JQogIGFkZF9yb3coUmF0ZSA9IDEyLjgsCiAgICAgICAgICBZZWFyID0gMjAxOCwKICAgICAgICAgIEdlbmRlciA9ICJBTEwiLAogICAgICAgICAgU3ViZ3JvdXAgPSAiQUxMIiwgCiAgICAgICAgICBUeXBlID0gIkxBVElOTy9BIFRPVEFMIikgJT4lCiAgYWRkX3JvdyhSYXRlID0gMTMuMywKICAgICAgICAgIFllYXIgPSAyMDE4LAogICAgICAgICAgR2VuZGVyID0gIkZFTUFMRSIsCiAgICAgICAgICBTdWJncm91cCA9ICJBTEwiLCAKICAgICAgICAgIFR5cGUgPSAiR0VOREVSIFRPVEFMIikgJT4lCiAgYWRkX3JvdyhSYXRlID0gMTIuMywKICAgICAgICAgIFllYXIgPSAyMDE4LAogICAgICAgICAgR2VuZGVyID0gIk1BTEUiLAogICAgICAgICAgU3ViZ3JvdXAgPSAiQUxMIiwgCiAgICAgICAgICBUeXBlID0gIkdFTkRFUiBUT1RBTCIpCmBgYAoKV2UgYWRkIHRoZSAyMDE4IGRhdGEgdG8gdGhlIGRhdGFmcmFtZQoKYGBge3J9CmRmMyA8LSBiaW5kX3Jvd3MoZGYzLAogICAgICAgICAgICAgICAgIGRmM18yMDE4KQpgYGAKCiMjIyBNYXAKCldlIHdpbGwgdXNlIG11bHRpcGxlIGltYWdlcyB0byBpbXBvcnQgdGhlIGRhdGEgb24gcGFnZSAzNiB0byBwcm9kdWNlIG1hcHMuIAoKPHN0eWxlPgpkaXYucmVkIHsgYmFja2dyb3VuZC1jb2xvcjojZmZjY2NiOyBib3JkZXItcmFkaXVzOiA1cHg7IHBhZGRpbmc6IDIwcHg7fQo8L3N0eWxlPgo8ZGl2IGNsYXNzID0gInJlZCI+CgoqKk1JQ0hBRUwgT05USVZFUk9TKioKCipUaGlzIGNvZGUgaXMgbm90IGNvbXBsZXRlLiBJZiB0aGVyZSBpcyB0aW1lLCB3ZSB3aWxsIHJldHVybiB0byBpdCEgTWFnaWNrIGlzIGhhdmluZyB0cm91YmxlIHdpdGggcXVhZHJhbnQgMSBhbmQgNC4gSSBjb3VsZCBub3QgZmlndXJlIG91dCB3aHkuKgo8L2Rpdj4KCmBgYHtyLCBldmFsPUZBTFNFfQpxdWFkcmFudDEgPC0gaW1hZ2VfcmVhZChoZXJlKCJpbWciLCAic3RhdGVfcXVhZHJhbnQxLnBuZyIpKQpxdWFkcmFudDIgPC0gaW1hZ2VfcmVhZChoZXJlKCJpbWciLCAic3RhdGVfcXVhZHJhbnQyLnBuZyIpKQpxdWFkcmFudDMgPC0gaW1hZ2VfcmVhZChoZXJlKCJpbWciLCAic3RhdGVfcXVhZHJhbnQzLnBuZyIpKQpxdWFkcmFudDQgPC0gaW1hZ2VfcmVhZChoZXJlKCJpbWciLCAic3RhdGVfcXVhZHJhbnQ0LnBuZyIpKQoKcXVhZHJhbnQxIDwtIG1hZ2ljazo6aW1hZ2Vfb2NyKHF1YWRyYW50MSkKcXVhZHJhbnQyIDwtIG1hZ2ljazo6aW1hZ2Vfb2NyKHF1YWRyYW50MikKcXVhZHJhbnQzIDwtIG1hZ2ljazo6aW1hZ2Vfb2NyKHF1YWRyYW50MykKcXVhZHJhbnQ0IDwtIG1hZ2ljazo6aW1hZ2Vfb2NyKHF1YWRyYW50NCkKCmxhYmVsc19xdWFkMV8zIDwtIHBhc3RlMChxdWFkcmFudDEsIHF1YWRyYW50MykKbGFiZWxzX3F1YWQyXzQgPC0gcGFzdGUwKHF1YWRyYW50MiwgcXVhZHJhbnQ0KQoKbGFiZWxzX3F1YWQxXzMgPC0gbGFiZWxzX3F1YWQxXzMgJT4lCiAgc3Ryc3BsaXQoIlxuIikgJT4lCiAgdW5saXN0KCkgJT4lCiAgYXNfdGliYmxlKCkKCmxhYmVsc19xdWFkMl80IDwtIGxhYmVsc19xdWFkMl80ICU+JQogIHN0cnNwbGl0KCJcbiIpICU+JQogIHVubGlzdCgpICU+JQogIGFzX3RpYmJsZSgpCgpkZjEgPC0gZGYxICU+JQogIGRwbHlyOjpzZWxlY3QodmFsdWUpICU+JQogIHB1bGwodmFsdWUpICU+JQogIHN0cl9zcGxpdCgiICIpCmBgYAoKYGBge3IsIGV2YWw9IEZBTFNFfQpkYXRhX21hcCA8LSBtYXBfZGF0YSgic3RhdGUiKSAlPiUKICBmaWx0ZXIocmVnaW9uPT0iY2FsaWZvcm5pYSIpCgp5ZWFycyA8LSBjKHNlcSgyMDA4LDIwMTYsYnk9MiksMjAxNykKCmluZGV4X3JlcCA8LSBkaW0oZGF0YV9tYXApWzFdCgpkYXRhX21hcCA8LSBiaW5kX3Jvd3MocmVwbGljYXRlKGxlbmd0aCh5ZWFycyksIGRhdGFfbWFwLCBzaW1wbGlmeSA9IEZBTFNFKSkKCmRhdGFfbWFwJHllYXIgPC0gcmVwKHllYXJzLCBlYWNoID0gaW5kZXhfcmVwKQoKZGF0YV9tYXAgPC0gZGF0YV9tYXAgJT4lCiAgZ3JvdXBfYnkocmVnaW9uLCB5ZWFyKSAlPiUKICBtdXRhdGUocmFua19yYW4gPSByYW5rKHllYXIsIHRpZXMubWV0aG9kID0gInJhbmRvbSIpKQoKZGF0YV9tYXAgPC0gZGF0YV9tYXBbb3JkZXIoZGF0YV9tYXAkb3JkZXIpLF0KCmxpYnJhcnkoZ2dhbmltYXRlKQoKZ2dwbG90KGRhdGFfbWFwLCBhZXMoeCA9IGxvbmcsIHkgPSBsYXQsIGdyb3VwID0gZ3JvdXAsIGZpbGw9cmFua19yYW4pKSArCiAgZ2VvbV9wb2x5Z29uKCkgKwogIHRyYW5zaXRpb25fdGltZSh0aW1lID0geWVhcikKCmBgYAoKIyMgKipEYXRhIEFuYWx5c2lzKioKKioqIAoKKipSZXBlYXRlZCBDcm9zcy1zZWN0aW9uYWwgRGF0YSoqCgpXZSBoYXZlIHBvb2xlZCAocmVwZWF0ZWQpIFtjcm9zcy1zZWN0aW9uYWxdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0Nyb3NzLXNlY3Rpb25hbF9kYXRhP29sZGZvcm1hdD10cnVlKSBkYXRhLgoKVGhpcyBpcyBkYXRhIHByb2R1Y2VkIGZyb20gcmVwZWF0ZWQgbWVhc3VyZW1lbnQgb2YgYSBbcG9wdWxhdGlvbl0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvUG9wdWxhdGlvbj9vbGRmb3JtYXQ9dHJ1ZSkgb3ZlciB0aW1lLgoKSXQgaXMgb2Z0ZW4gaW5mZWFzaWJsZSB0byBjb2xsZWN0IGRhdGEgZm9yIGFuIGVudGlyZSBwb3B1bGF0aW9uIGF0IG9uY2UuIEhvd2V2ZXIsIHdlIGNhbiBzdGlsbCBvYnRhaW4gbWVhbmluZ2Z1bCBtZWFzdXJlcyB1c2luZyBhIHJhbmRvbSBbc2FtcGxlXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9TYW1wbGluZ18oc3RhdGlzdGljcyk/b2xkZm9ybWF0PXRydWUpIG9mIHRoZSBwb3B1bGF0aW9uLiAKCkF0IHNwZWNpZmljIHRpbWUtcG9pbnRzLCBkYXRhIGlzIGNvbGxlY3RlZCBmcm9tIGEgc2FtcGxlIG9mIHRoZSBwb3B1bGF0aW9uLiBUaGUgaW5kaXZpZHVhbHMgaW4gZWFjaCBzYW1wbGUgYXJlIG5vdCBuZWNlc3NhcmlseSB0aGUgc2FtZSBpbmRpdmlkdWFscy4gVGhpcyBzZXBhcmF0ZXMgcG9vbGVkIGNyb3NzLXNlY3Rpb25hbCBkYXRhIGZyb20gcGFuZWwgZGF0YSwgd2hpY2ggaXMgbG9uZ2l0dWRpbmFsIGRhdGEgZnJvbSByZXBlYXRlZCBtZWFzdXJlbWVudCBvZiB0aGUgc2FtZSBwZW9wbGUuICAgCgpCeSBzYW1wbGluZyBmcm9tIGEgcG9wdWxhdGlvbiBhdCBtdWx0aXBsZSB0aW1lIHBvaW50cywgd2UgY2FuIGdlbmVyYXRlIHBvcHVsYXRpb24gbGV2ZWwgc3RhdGlzdGljcy4gQWx0aG91Z2ggdGhlc2Ugc3RhdGlzdGljcyBoYXZlIHNvbWUgcmFuZG9tIGVycm9yLCB0aGV5IGNhbiBwcm92aWRlIGluc2lnaHQgaW50byBob3cgdGhlIG1lYXN1cmUgdmFyaWFibGUgaXMgY2hhbmdpbmcgaW4gYSBwb3B1bGF0aW9uIG92ZXIgdGltZS4KCldlIGNhbiBhY2NvbXBsaXNoIHRoaXMgYnkgcGxvdHRpbmcgdGhlIG1lYXN1cmVkIHZhbHVlcyBvdmVyIHRpbWUuIFNvbWV0aW1lcywgaG93ZXZlciwgdGhlIHRyZW5kIGlzbid0IGV4YWN0bHkgY2xlYXIuIEZvcnR1bmF0ZWx5LCB0aGVyZSBhcmUgc3RhdGlzdGljYWwgbWV0aG9kcyB0byByZXNvbHZlIHRoaXMgaXNzdWUuCgpUaGUgTWFubi1LZW5kYWxsIHRyZW5kIHRlc3TigJRhIHZhcmlhdGlvbiBvZiB0aGUgW0tlbmRhbGwgcmFuayBjb3JyZWxhdGlvbiBjb2VmZmljaWVudF0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvS2VuZGFsbF9yYW5rX2NvcnJlbGF0aW9uX2NvZWZmaWNpZW50P29sZGZvcm1hdD10cnVlKeKAlHRlc3RzIHdoZXRoZXIgdGhlcmUgaXMgYSBtb25vdG9uaWMgYXNzb2NpYXRpb24sIGFuIGFzc29jaWF0aW9uIHRoYXQgZG9lcyBub3QgaW5jcmVhc2Ugb3IgZGVjcmVhc2UgYnV0IHJlbWFpbnMgc3RhdGljIGFjcm9zcyBhIGRpbWVuc2lvbi4KClJlY2FsbCB0aGUgeW91dGggZGlzY29ubmVjdGlvbiByYXRlcyBmb3IgTmF0aXZlIEFtZXJpY2Fucywgc29tZSBvZiB0aGUgaGlnaGVzdCBpbiB0aGUgZmlyc3QgdGFibGUgd2UgZXhhbWluZWQuIAoKYGBge3J9CmltYWdlX2V4YW1wbGUKYGBgCgpMZXQncyBjb25kdWN0IGEgTWFubi1LZW5kYWxsIHRlc3QgZm9yIHRyZW5kLgoKV2UgY2FuIGFjY29tcGxpc2ggdGhpcyB3aXRoIHRoZSBgS2VuZGFsbDo6TWFubktlbmRhbGwoKWAgZnVuY3Rpb24uIFRoZSBgS2VuZGFsbDo6TWFubktlbmRhbGwoKWAgYWNjZXB0cyBhIHZlY3RvciBvZiBkYXRhIGZvciB3aGljaCBhIHRyZW5kIG1heSBiZSBvYnNlcnZlZC4gW0NvbnN1bHRpbmcgdGhlIGRvY3VtZW50YXRpb24gZm9yIHRoZSBgS2VuZGFsbDo6TWFubktlbmRhbGwoKWAgZnVuY3Rpb24gYXZhaWxhYmxlIG9uIENSQU5dKGh0dHBzOi8vcmRyci5pby9jcmFuL0tlbmRhbGwvbWFuL01hbm5LZW5kYWxsLmh0bWwpLCB3ZSBjYW4gInRlc3QgZm9yIGEgYSBtb25vdG9uaWMgdHJlbmQgaW4gYSB0aW1lIHNlcmllcyIuCgpgYGB7cn0KZGYxICU+JQogIGZpbHRlcihHZW5kZXIgPT0gIkFMTCIsCiAgICAgICAgIFJhY2UgPT0gIk5BVElWRSBBTUVSSUNBTiIpICU+JQogIHB1bGwoUmF0ZSkgJT4lCiAgTWFubktlbmRhbGwoLikgJT4lCiAgc3VtbWFyeSgpCmBgYAoKVGhlcmUgZG9lcyBub3QgYXBwZWFyIHRvIGJlIGEgY2hhbmdlIGluIHRoZSB0cmVuZC4gSG93ZXZlciwgaXQncyBpbXBvcnRhbnQgdG8gbm90ZSB0aGF0IHdlIG9ubHkgaGF2ZSBgciBsZW5ndGgoZGYxICU+JSBmaWx0ZXIoR2VuZGVyID09ICJBTEwiLCBSYWNlID09ICJOQVRJVkUgQU1FUklDQU4iKSAlPiUgcHVsbChSYXRlKSlgIG9ic2VydmF0aW9ucy4KCldlIGNhbiBhbHNvIGV4cGxvcmUgdGhlIHRyZW5kIHVzaW5nIFtzaW1wbGUgbGluZWFyIHJlZ3Jlc3Npb25dKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL1NpbXBsZV9saW5lYXJfcmVncmVzc2lvbj9vbGRmb3JtYXQ9dHJ1ZSkuIAoKYGBge3J9CmRmMSAlPiUKICBmaWx0ZXIoR2VuZGVyID09ICJBTEwiLAogICAgICAgICBSYWNlID09ICJOQVRJVkUgQU1FUklDQU4iKSAlPiUKICBsbShSYXRlIH4gWWVhciwgZGF0YSA9IC4pICU+JQogIHN1bW1hcnkoKQpgYGAKCkZvciBlYWNoIG9uZSB5ZWFyIGNoYW5nZSwgdGhlIG1lYW4gaW5jcmVhc2UgaW4gZGlzY29ubmVjdGlvbiByYXRlcyBpcyBgciAoZGYxICU+JSBmaWx0ZXIoR2VuZGVyID09ICJBTEwiLCBSYWNlID09ICJOQVRJVkUgQU1FUklDQU4iKSAlPiUgbG0oUmF0ZSB+IFllYXIsIGRhdGEgPSAuKSlbWyJjb2VmZmljaWVudHMiXV1bIlllYXIiXWAuIFRoaXMgcmVsYXRpb25zaGlwIGlzIG5vdCBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50LiBBZ2Fpbiwgd2UgYXJlIGxhcmdlbHkgbGltaXRlZCBieSB0aGUgbnVtYmVyIG9mIG9ic2VydmF0aW9ucyBpbiB0aGlzIGRhdGFzZXQuIAoKV2UgY2FuIHZpc3VhbGl6ZSB0aGUgcmVsYXRpb25zaGlwIGFib3ZlLgoKYGBge3J9CmRmMSAlPiUKICBmaWx0ZXIoR2VuZGVyID09ICJBTEwiLAogICAgICAgICBSYWNlID09ICJOQVRJVkUgQU1FUklDQU4iKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBZZWFyLCB5ID0gUmF0ZSkpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBjb2xvciA9ICJyZWQiKSArIAogIGdlb21fcG9pbnQoKSArIAogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoMjAwOCwgMjAxOCwgYnkgPSAxKSwKICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gc2VxKDIwMDgsIDIwMTgsIGJ5ID0gMSksCiAgICAgICAgICAgICAgICAgICAgIGxpbWl0cyA9IGMoMjAwOCwgMjAxOCkpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIGxhYnModGl0bGUgPSAiWW91dGggRGlzY29ubmVjdGlvbiBSYXRlcyBvZiBOYXRpdmUgQW1lcmljYW4gWW91dGgiLAogICAgICAgc3VidGl0bGUgPSAiMjAwOCAtIDIwMTciLAogICAgICAgeCA9ICJZZWFyIiwKICAgICAgIHkgPSAiRGlzY29ubmVjdGlvbiBSYXRlIikKYGBgCgpBcyB3ZSBjYW4gc2VlLCB0aGVyZSBpcyBhIGxhcmdlIGFtb3VudCBvZiB1bmNlcnRhaW50eSBhcm91bmQgdGhlIGZpdHRlZCBsaW5lLiAKCkxldCdzIHZpc3VhbGl6ZSB0aGUgZGF0YSEgCgojIyAqKkRhdGEgVmlzdWFsaXphdGlvbioqCioqKiAKCkxldCdzIHJlcHJvZHVjZSB0aGUgZXhhbXBsZSBiZWxvdy4KCmBgYHtyLCBvdXQud2lkdGggPSAiMTAwJSIsIGVjaG8gPSBGQUxTRSwgZmlnLmFsaWduID0iY2VudGVyIn0KaW5jbHVkZV9ncmFwaGljcyhoZXJlOjpoZXJlKCJpbWciLCAiTWFraW5nX3RoZV9Db25uZWN0aW9uX3Bsb3QucG5nIikpCmBgYAoKV2UgY2FuIGNyZWF0ZSBhIHZlcnNpb24gb2YgdGhlIGFib3ZlIGV4YW1wbGUgd2l0aCBgZ2dwbG90YCBmcm9tIGB0aWR5dmVyc2VgLgoKVGhlcmUgYXJlIGNvbG9yIGlkZW50aWZ5aW5nIHdlYnNpdGVzIG9ubHkgc3VjaCBhcyBbdGhpc10oaHR0cHM6Ly9pbWFnZWNvbG9ycGlja2VyLmNvbS9lbi8pLgoKVXNpbmcgb25lIG9mIHRoZXNlIHdlYnNpdGVzLCB3ZSBpZGVudGlmeSB0aGUgW2hleCB0cmlwbGV0XShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9XZWJfY29sb3JzP29sZGZvcm1hdD10cnVlKSBmb3IgdGhlIGNvbG9yIHVzZWQgaW4gdGhlIHZpc3VhbGl6YXRpb24gaW5jbHVkZWQgaW4gdGhlIFBERjogYCMwMDgzOTNgLiAKCmBgYHtyfQpmYV9maWd1cmluZSA8LSBpbWFnZV9yZWFkKCJodHRwczovL3VwbG9hZC53aWtpbWVkaWEub3JnL3dpa2lwZWRpYS9jb21tb25zLzcvN2MvVXNlcl9mb250X2F3ZXNvbWUuc3ZnIikKCmZhX2ZpZ3VyaW5lIDwtIGltYWdlX2ZpbGwoZmFfZmlndXJpbmUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSAiIzAwODM5MyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgIHBvaW50ID0gIis4MDArODAwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBmdXp6ID0gMCkKCmZhX2ZpZ3VyaW5lIDwtIGltYWdlX2ZpbGwoZmFfZmlndXJpbmUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSAiIzAwODM5MyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgIHBvaW50ID0gIis4MDArMTAwMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgZnV6eiA9IDApCgpkZjEgJT4lCiAgZmlsdGVyKFR5cGUgPT0gIlJBQ0UgVE9UQUwiKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBZZWFyLCB5ID0gUmF0ZSwgZ3JvdXA9UmFjZSkpICsKICBnZW9tX2xpbmUoY29sb3IgPSAiIzAwODM5MyIsIHNpemUgPSAwLjUpICsKICBnZW9tX3BvaW50KGNvbG9yID0gIiMwMDgzOTMiLCBzaXplID0gMykgKwogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoMjAwOCwyMDE4LCBieT0xKSwKICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYygyMDA4LDIwMTgpKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHNlcSg1LDMwLCBieSA9NSksCiAgICAgICAgICAgICAgICAgICAgIGxpbWl0cyA9IGMoNSwzMCkpICsKICBkcmF3X2ltYWdlKGZhX2ZpZ3VyaW5lLCB4ID0gMjAxNywgeSA9IDIzLjUsIHNjYWxlID0gMikgKwogIGRyYXdfaW1hZ2UoZmFfZmlndXJpbmUsIHggPSAyMDE3LCB5ID0gMTcuNSwgc2NhbGUgPSAyKSArCiAgZHJhd19pbWFnZShmYV9maWd1cmluZSwgeCA9IDIwMTcsIHkgPSAxMywgc2NhbGUgPSAyKSArCiAgZHJhd19pbWFnZShmYV9maWd1cmluZSwgeCA9IDIwMTcsIHkgPSA5LCBzY2FsZSA9IDIpICsKICBkcmF3X2ltYWdlKGZhX2ZpZ3VyaW5lLCB4ID0gMjAxNywgeSA9IDYuNSwgc2NhbGUgPSAyKSArCiAgbGFicyh0aXRsZSA9ICJGSUdVUkUgMSBZT1VUSCBESVNDT05ORUNUSU9OIEJZIFJBQ0UgQU5EIEVUSE5JQ0lUWSwgMjAwOCAtIDIwMTciLAogICAgICAgeSA9ICJZT1VUSCBESVNDT05ORUNUSU9OICglKSIpICsKICB0aGVtZV9jbGFzc2ljKCkgKwogIHRoZW1lKHRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9ICIjMDA4MzkzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmYWNlID0gImJvbGQiKSwKICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCkpCmBgYAoKV2UgY2FuIGJ1aWxkIG9mZiBvZiB0aGlzIGlkZWEsIHVzaW5nIGEgY3VzdG9tIGNvbG9yIHBhbGV0dGUgdG8gY3JlYXRlIGEgZ3JhZGllbnQgYmFzZWQgb2ZmIHRoZSBjb2xvciB1c2VkLiAKCmBgYHtyfQpjdXN0b21fcGFsIDwtIGNvbG9yUmFtcFBhbGV0dGUoYygid2hpdGUiLCAiIzAwODM5MyIpKQpnZW5kZXJfbiA8LSAzCgphc2lhbl90b3RhbCA8LSBkZjIgJT4lCiAgZmlsdGVyKFllYXIgPT0gMjAxNykgJT4lCiAgZmlsdGVyKEdlbmRlciA9PSAiQUxMIiwKICAgICAgICAgU3ViZ3JvdXAgPT0gIkFMTCIpICU+JQogIHB1bGwoUmF0ZSkKCmRmMiAlPiUKICBmaWx0ZXIoWWVhciA9PSAyMDE3KSAlPiUKICBjb21wbGV0ZShHZW5kZXIsIFN1Ymdyb3VwKSAlPiUKICBncm91cF9ieShHZW5kZXIpICU+JQogIG11dGF0ZShzdWJfcmFuayA9IHJhbmsoUmF0ZSwgdGllcy5tZXRob2QgPSAibWluIikpICU+JQogIGdyb3VwX2J5KFN1Ymdyb3VwKSAlPiUKICBtdXRhdGUocmFua19hbGwgPSBzdWJfcmFua1tHZW5kZXIgPT0gIkFMTCJdKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgbXV0YXRlKFN1Ymdyb3VwID0gZmN0X3Jlb3JkZXIoU3ViZ3JvdXAsIHJhbmtfYWxsKSkgJT4lCiAgZ2dwbG90KGFlcyh4ID0gU3ViZ3JvdXAsIHkgPSBSYXRlLCBmaWxsID0gR2VuZGVyKSkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IGFzaWFuX3RvdGFsLCAKICAgICAgICAgICAgIGNvbG9yID0gImJsYWNrIiwKICAgICAgICAgICAgIGxpbmV0eXBlID0gMikgKyAKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwKICAgICAgICAgICBjb2xvciA9ICJ0cmFuc3BhcmVudCIsCiAgICAgICAgICAgc2l6ZSA9IDAuNSwKICAgICAgICAgICBwb3NpdGlvbiA9ICJkb2RnZSIsCiAgICAgICAgICAgd2lkdGggPSAwLjUpICsKICBsYWJzKHRpdGxlID0gIkZJR1VSRSBYIFlPVVRIIERJU0NPTk5FQ1RJT04gQlkgQVNJQU4gU1VCR1JPVVAsIDIwMTciLAogICAgICAgc3VidGl0bGUgPSAiT1JERVJFRCBCWSBPVkVSQUxMIERJU0NPTk5FQ1RJT04iLAogICAgICAgeSA9ICJZT1VUSCBESVNDT05ORUNUSU9OICglKSIsCiAgICAgICBmaWxsID0gIkdlbmRlciIpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSByZXYoY3VzdG9tX3BhbChnZW5kZXJfbiArIDEpKSkgKwogIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMCwyMCwyKSwKICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gc2VxKDAsMjAsMiksCiAgICAgICAgICAgICAgICAgICAgIGxpbWl0cyA9IGMoMCwyMCkpICsKICB0aGVtZV9jbGFzc2ljKCkgKwogIHRoZW1lKHRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9ICIjMDA4MzkzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmYWNlID0gImJvbGQiKSwKICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxKSkgKwogIGFubm90YXRlKCJ0ZXh0IiwgbGFiZWwgPSAnYm9sZCgiQVNJQU4gVE9UQUwiKScsCiAgICAgICAgICAgY29sb3IgPSAiIzAwODM5MyIsIAogICAgICAgICAgIHNpemUgPSAzLAogICAgICAgICAgIHggPSAxLjIsCiAgICAgICAgICAgeSA9IGFzaWFuX3RvdGFsICsgMSwKICAgICAgICAgICBwYXJzZSA9IFRSVUUpCmBgYAoKRnJvbSB0aGUgYWJvdmUgcGxvdCwgaXQgYmVjb21lcyBhcHBhcmVudCB0aGF0IHRoZSBIbW9uZyBzdWJncm91cCBwcm9kdWNlcyBhIHNtYWxsIHByb3BvcnRpb24gb2YgdGhlIHRvdGFsIG51bWJlciBvZiBhc2lhbiBkaXNjb25uZWN0ZWQgeW91dGguIFRoZSBBc2lhbiB0b3RhbCB5b3V0aCBkaXNjb25uZWN0aW9uIHJhdGUgaXMgbW9yZSBhbGlrZSB0aGUgeW91dGggZGlzY29ubmVjdGlvbiByYXRlcyBmb3IgYWxsIG90aGVyIHN1Ymdyb3VwcyB0aGFuIHRoZSBIbW9uZyB5b3V0aCBkaXNjb25uZWN0aW9uIHJhdGUuCgpXZSBjYW4gY29uZmlybSB0aGlzIGJ5IHJldmlzaXRpbmcgdGhlIHRhYmxlLgoKYGBge3J9CmltYWdlMgpgYGAKClRoZSBIbW9uZyBncm91cCByZXByZXNlbnRzIGByIHJvdW5kKCg4MzAwKjEwMCkvMTQ1NjAwKWAlIG9mIGFsbCBBc2lhbiBkaXNjb25uZWN0ZWQgeW91dGguIAoKVGhpcyBzaG93cyB0aGUgaW1wb3J0YW5jZSBvZiBhZGRpbmcgc21hbGwgZGV0YWlscyBzdWNoIGFzIHRoZSBjb21wb3NpdGUgbGluZSB0byBwbG90cy4gSXQgaGVscHMgcHJvdmlkZSBhIHNpbXBsZSB5ZXQgbnVhbmNlZCBwaWN0dXJlIG9mIHdoYXQgaXMgZ29pbmcgb24uIAoKTGFzdGx5LCB3ZSBjYW4gYWRkIGFubm90YXRpb25zIHRvIGFkZCBwcm92aWRlIGV2ZW4gbW9yZSBkZXB0aCB0byB0aGUgdmlzdWFsaXphdGlvbi4gCgpgYGB7cn0KbGF0aW5vX2FfdG90YWwgPC0gZGYzICU+JQogIGZpbHRlcihZZWFyID09IDIwMTcpICU+JQogIGZpbHRlcihHZW5kZXIgPT0gIkFMTCIsCiAgICAgICAgIFN1Ymdyb3VwID09ICJBTEwiKSAlPiUKICBwdWxsKFJhdGUpCgpkZjMgJT4lCiAgZmlsdGVyKFllYXIgPT0gMjAxNykgJT4lCiAgY29tcGxldGUoR2VuZGVyLCBTdWJncm91cCkgJT4lCiAgZ3JvdXBfYnkoR2VuZGVyKSAlPiUKICBtdXRhdGUoc3ViX3JhbmsgPSByYW5rKFJhdGUsIHRpZXMubWV0aG9kID0gIm1pbiIpKSAlPiUKICBncm91cF9ieShTdWJncm91cCkgJT4lCiAgbXV0YXRlKHJhbmtfYWxsID0gc3ViX3JhbmtbR2VuZGVyID09ICJBTEwiXSkgJT4lCiAgdW5ncm91cCgpICU+JQogIG11dGF0ZShTdWJncm91cCA9IGZjdF9yZW9yZGVyKFN1Ymdyb3VwLCByYW5rX2FsbCkpICU+JQogIGdncGxvdChhZXMoeCA9IFN1Ymdyb3VwLCB5ID0gUmF0ZSwgZmlsbCA9IEdlbmRlcikpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSBsYXRpbm9fYV90b3RhbCwgCiAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIsCiAgICAgICAgICAgICBsaW5ldHlwZSA9IDIpICsgCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsCiAgICAgICAgICAgY29sb3IgPSAidHJhbnNwYXJlbnQiLAogICAgICAgICAgIHNpemUgPSAwLjUsCiAgICAgICAgICAgcG9zaXRpb24gPSAiZG9kZ2UiLAogICAgICAgICAgIHdpZHRoID0gMC41KSArCiAgbGFicyh0aXRsZSA9ICJGSUdVUkUgWCBZT1VUSCBESVNDT05ORUNUSU9OIEJZIExBVElOTy9BIFNVQkdST1VQLCAyMDE3IiwKICAgICAgIHN1YnRpdGxlID0gIk9SREVSRUQgQlkgT1ZFUkFMTCBESVNDT05ORUNUSU9OIiwKICAgICAgIHkgPSAiWU9VVEggRElTQ09OTkVDVElPTiAoJSkiLAogICAgICAgZmlsbCA9ICJHZW5kZXIiKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gcmV2KGN1c3RvbV9wYWwoZ2VuZGVyX24gKyAxKSkpICsKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsMjAsMiksCiAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IHNlcSgwLDIwLDIpLAogICAgICAgICAgICAgICAgICAgICBsaW1pdHMgPSBjKDAsMjApKSArCiAgdGhlbWVfY2xhc3NpYygpICsKICB0aGVtZSh0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSAiIzAwODM5MyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmFjZSA9ICJib2xkIiksCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0ID0gMSkpICsKICBhbm5vdGF0ZSgidGV4dCIsIGxhYmVsID0gJ2JvbGQoIkxBVElOTyBUT1RBTCIpJywKICAgICAgICAgICBjb2xvciA9ICIjMDA4MzkzIiwgCiAgICAgICAgICAgc2l6ZSA9IDMsCiAgICAgICAgICAgeCA9IDEuMiwKICAgICAgICAgICB5ID0gbGF0aW5vX2FfdG90YWwgKyAxLAogICAgICAgICAgIHBhcnNlID0gVFJVRSkKYGBgCgpgYGB7cn0KZGYyICU+JQogIGNvbXBsZXRlKEdlbmRlciwgU3ViZ3JvdXAsIFllYXIpICU+JQogIGdyb3VwX2J5KFN1Ymdyb3VwKSAlPiUKICBtdXRhdGUobWlzc2luZyA9IHN1bShpcy5uYShSYXRlKSkpICU+JQogIGZpbHRlcihtaXNzaW5nID09IDApICU+JQogIGRwbHlyOjpzZWxlY3QoLW1pc3NpbmcpICU+JQogIHVuZ3JvdXAoKSAlPiUKICBncm91cF9ieShHZW5kZXIpICU+JQogIG11dGF0ZShzdWJfcmFuayA9IHJhbmsoUmF0ZSwgdGllcy5tZXRob2QgPSAibWluIikpICU+JQogIGdyb3VwX2J5KFN1Ymdyb3VwLCBZZWFyKSAlPiUKICBtdXRhdGUocmFua19hbGwgPSBzdWJfcmFua1tHZW5kZXIgPT0gIkFMTCJdKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgZ3JvdXBfYnkoWWVhcikgJT4lCiAgbXV0YXRlKHRocmVzaG9sZCA9IFJhdGVbR2VuZGVyID09ICJBTEwiICYgU3ViZ3JvdXAgPT0gIkFMTCJdKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgbXV0YXRlKFN1Ymdyb3VwID0gZmN0X3Jlb3JkZXIoU3ViZ3JvdXAsIHJhbmtfYWxsKSkgJT4lCiAgZ2dwbG90KGFlcyh4ID0gU3ViZ3JvdXAsIHkgPSBSYXRlLCBmaWxsID0gR2VuZGVyKSkgKwogIGZhY2V0X3dyYXAoWWVhciB+LiwgbmNvbCA9IDEpICsKICBnZW9tX2hsaW5lKGFlcyh5aW50ZXJjZXB0ID0gdGhyZXNob2xkKSwgbGluZXR5cGUgPSAyKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsCiAgICAgICAgICAgY29sb3IgPSAidHJhbnNwYXJlbnQiLAogICAgICAgICAgIHNpemUgPSAwLjUsCiAgICAgICAgICAgcG9zaXRpb24gPSAiZG9kZ2UiLAogICAgICAgICAgIHdpZHRoID0gMC41KSArCiAgbGFicyh0aXRsZSA9ICJGSUdVUkUgWCBZT1VUSCBESVNDT05ORUNUSU9OIEJZIEFTSUFOIFNVQkdST1VQLCAyMDE3LTIwMTgiLAogICAgICAgc3VidGl0bGUgPSAiT1JERVJFRCBCWSBPVkVSQUxMIERJU0NPTk5FQ1RJT04iLAogICAgICAgeSA9ICJZT1VUSCBESVNDT05ORUNUSU9OICglKSIsCiAgICAgICBmaWxsID0gIkdlbmRlciIpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSByZXYoY3VzdG9tX3BhbChnZW5kZXJfbiArIDEpKSkgKwogIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMCwxMCwyKSwKICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gc2VxKDAsMTAsMiksCiAgICAgICAgICAgICAgICAgICAgIGxpbWl0cyA9IGMoMCwxMCkpICsKICB0aGVtZV9jbGFzc2ljKCkgKwogIHRoZW1lKHRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9ICIjMDA4MzkzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmYWNlID0gImJvbGQiKSwKICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxKSkKYGBgCgpgYGB7cn0KZGYzICU+JQogIGNvbXBsZXRlKEdlbmRlciwgU3ViZ3JvdXAsIFllYXIpICU+JQogIGdyb3VwX2J5KFN1Ymdyb3VwKSAlPiUKICBtdXRhdGUobWlzc2luZyA9IHN1bShpcy5uYShSYXRlKSkpICU+JQogIGZpbHRlcihtaXNzaW5nID09IDApICU+JQogIGRwbHlyOjpzZWxlY3QoLW1pc3NpbmcpICU+JQogIHVuZ3JvdXAoKSAlPiUKICBncm91cF9ieShHZW5kZXIpICU+JQogIG11dGF0ZShzdWJfcmFuayA9IHJhbmsoUmF0ZSwgdGllcy5tZXRob2QgPSAibWluIikpICU+JQogIGdyb3VwX2J5KFN1Ymdyb3VwLCBZZWFyKSAlPiUKICBtdXRhdGUocmFua19hbGwgPSBzdWJfcmFua1tHZW5kZXIgPT0gIkFMTCJdKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgZ3JvdXBfYnkoWWVhcikgJT4lCiAgbXV0YXRlKHRocmVzaG9sZCA9IFJhdGVbR2VuZGVyID09ICJBTEwiICYgU3ViZ3JvdXAgPT0gIkFMTCJdKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgbXV0YXRlKFN1Ymdyb3VwID0gZmN0X3Jlb3JkZXIoU3ViZ3JvdXAsIHJhbmtfYWxsKSkgJT4lCiAgZ2dwbG90KGFlcyh4ID0gU3ViZ3JvdXAsIHkgPSBSYXRlLCBmaWxsID0gR2VuZGVyKSkgKwogIGZhY2V0X3dyYXAoWWVhciB+LiwgbmNvbCA9IDEpICsKICBnZW9tX2hsaW5lKGFlcyh5aW50ZXJjZXB0ID0gdGhyZXNob2xkKSwgbGluZXR5cGUgPSAyKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsCiAgICAgICAgICAgY29sb3IgPSAidHJhbnNwYXJlbnQiLAogICAgICAgICAgIHNpemUgPSAwLjUsCiAgICAgICAgICAgcG9zaXRpb24gPSAiZG9kZ2UiLAogICAgICAgICAgIHdpZHRoID0gMC41KSArCiAgbGFicyh0aXRsZSA9ICJGSUdVUkUgWCBZT1VUSCBESVNDT05ORUNUSU9OIEJZIExBVElOTy9BIFNVQkdST1VQLCAyMDE3IiwKICAgICAgIHN1YnRpdGxlID0gIk9SREVSRUQgQlkgT1ZFUkFMTCBESVNDT05ORUNUSU9OIiwKICAgICAgIHkgPSAiWU9VVEggRElTQ09OTkVDVElPTiAoJSkiLAogICAgICAgZmlsbCA9ICJHZW5kZXIiKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gcmV2KGN1c3RvbV9wYWwoZ2VuZGVyX24gKyAxKSkpICsKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsMjAsMiksCiAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IHNlcSgwLDIwLDIpLAogICAgICAgICAgICAgICAgICAgICBsaW1pdHMgPSBjKDAsMjApKSArCiAgdGhlbWVfY2xhc3NpYygpICsKICB0aGVtZSh0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSAiIzAwODM5MyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmFjZSA9ICJib2xkIiksCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0ID0gMSkpCmBgYAoKIyMgKipTdW1tYXJ5KioKKioqIAoKIyMgKipTdWdnZXN0ZWQgSG9tZXdvcmsqKgoqKiogCgoxKSBGaW5kIGFub3RoZXIgdGFibGUgaW4gdGhlIGRvY3VtZW50LiBGaW5kIGRpZmZlcmVuY2VzIGJldHdlZW4gZ3JvdXBzIHdpdGggdGhlIHByb2Nlc3MgZGVzY3JpYmVkIGFib3ZlLiAKCiMjICoqSGVscGZ1bCBMaW5rcyoqCioqKiAKCgphdm9jYWRvKlRoaXMgY29uY2VwdHMgbGlzdGVkIGhlcmUgbXVzdCBiZSByZXZpc2l0ZWQuKgoKCjx1PlRlcm1zIGFuZCBjb25jZXB0cyBjb3ZlcmVkOjwvdT4gIAoKW1RpZHl2ZXJzZV0oaHR0cHM6Ly93d3cudGlkeXZlcnNlLm9yZy8pe3RhcmdldD0iX2JsYW5rIn0gIApbUlN0dWRpbyBjaGVhdHNoZWV0c10oaHR0cHM6Ly9yc3R1ZGlvLmNvbS9yZXNvdXJjZXMvY2hlYXRzaGVldHMvKXt0YXJnZXQ9Il9ibGFuayJ9ICAKW0luZmVyZW5jZV0oaHR0cHM6Ly93d3cuYnJpdGFubmljYS5jb20vc2NpZW5jZS9pbmZlcmVuY2Utc3RhdGlzdGljcyl7dGFyZ2V0PSJfYmxhbmsifSAgCltSZWdyZXNzaW9uXShodHRwczovL2xpbmRlbG9ldi5naXRodWIuaW8vdGVzdHMtYXMtbGluZWFyLyl7dGFyZ2V0PSJfYmxhbmsifSAgCltEaWZmZXJlbnQgdHlwZXMgb2YgcmVncmVzc2lvbl0oaHR0cHM6Ly93d3cuYW5hbHl0aWNzdmlkaHlhLmNvbS9ibG9nLzIwMTUvMDgvY29tcHJlaGVuc2l2ZS1ndWlkZS1yZWdyZXNzaW9uLyl7dGFyZ2V0PSJfYmxhbmsifSAgCltPcmRpbmFyeSBsZWFzdCBzcXVhcmVzIG1ldGhvZF0oaHR0cDovL3NldG9zYS5pby9ldi9vcmRpbmFyeS1sZWFzdC1zcXVhcmVzLXJlZ3Jlc3Npb24vKXt0YXJnZXQ9Il9ibGFuayJ9ICAKW1Jlc2lkdWFsXShodHRwczovL3d3dy5zdGF0aXN0aWNzaG93dG8uZGF0YXNjaWVuY2VjZW50cmFsLmNvbS9yZXNpZHVhbC8pe3RhcmdldD0iX2JsYW5rIn0gIAoKPHU+UGFja2FnZXMgdXNlZCBpbiB0aGlzIGNhc2Ugc3R1ZHk6IDwvdT4KCiBQYWNrYWdlICAgfCBVc2UgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCi0tLS0tLS0tLS0gfC0tLS0tLS0tLS0tLS0KWyoqaGVyZSoqXShodHRwczovL2dpdGh1Yi5jb20vamVubnliYy9oZXJlX2hlcmUpe3RhcmdldD0iX2JsYW5rIn0gICAgICAgfCB0byBlYXNpbHkgbG9hZCBhbmQgc2F2ZSBkYXRhClsqKnRpZHl2ZXJzZSoqXShodHRwczovL3JlYWRyLnRpZHl2ZXJzZS5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9ICAgICAgfCBmb3IgZGF0YSBzY2llbmNlIG9wZXJhdGlvbnMKWyoqcGRmdG9vbHMqKl0oaHR0cHM6Ly9yZWFkci50aWR5dmVyc2Uub3JnLyl7dGFyZ2V0PSJfYmxhbmsifSAgICAgIHwgdG8gbWFuYWdlIFBERiBkb2N1bWVudHMKWyoqbWFnaWNrKipdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9tYWdpY2svdmlnbmV0dGVzL2ludHJvLmh0bWwjS2VybmVsX2NvbnZvbHV0aW9uKXt0YXJnZXQ9Il9ibGFuayJ9ICAgICAgfCBmb3IgaW1hZ2UgcHJvY2Vzc2luZyAKCiMjIEFja25vd2xlZGdlbWVudHMKCldlIHdvdWxkIGxpa2UgdG8gYWNrbm93bGVkZ2UgW1RhbWFyIE1lbmRlbHNvbl0oaHR0cHM6Ly93d3cuamhzcGguZWR1L2ZhY3VsdHkvZGlyZWN0b3J5L3Byb2ZpbGUvMTc3MC90YW1hci1tZW5kZWxzb24pIGZvciBhc3Npc3RpbmcgaW4gZnJhbWluZyB0aGUgbWFqb3IgZGlyZWN0aW9uIG9mIHRoZSBjYXNlIHN0dWR5LgoKV2Ugd291bGQgYWxzbyBsaWtlIHRvIGFja25vd2xlZGdlIHRoZSBbQmxvb21iZXJnIEFtZXJpY2FuIEhlYWx0aCBJbml0aWF0aXZlXShodHRwczovL2FtZXJpY2FuaGVhbHRoLmpodS5lZHUvKSBmb3IgZnVuZGluZyB0aGlzIHdvcmsuIA==